🐛 Fix window capture to properly clip to app windows

Previously, window capture was falling back to fullscreen because it couldn't
get window IDs. Now using window bounds (position + size) with screencapture's
-R flag to properly capture only the app window content.

Changes:
- Use System Events to get window position and size
- Build screencapture -R command with x,y,width,height
- Added captureWindowByIndex for multi-window scenarios
- Proper error handling with fallback to fullscreen

This ensures AI analysis and screenshots only show the targeted app,
not the entire desktop.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Peter Steinberger 2025-05-22 21:44:11 +02:00
parent e1da1b7319
commit 3515285897

View file

@ -804,16 +804,29 @@ on captureScreenshot(outputPath, captureMode, appName)
-- Build screencapture command based on mode -- Build screencapture command based on mode
set screencaptureCmd to "screencapture -x" set screencaptureCmd to "screencapture -x"
if captureMode is "window" then if captureMode is "window" and appName is not "fullscreen" then
-- IMPORTANT: Do NOT use -o -W flags as they require user interaction! -- IMPORTANT: Do NOT use -o -W flags as they require user interaction!
-- Instead, get the window ID of the frontmost window programmatically -- Instead, capture the window using its bounds (position and size)
try try
-- Get the window ID of the frontmost window of the frontmost app tell application "System Events"
set windowID to do shell script "osascript -e 'tell application \"System Events\" to get the id of the first window of (first process whose frontmost is true)' 2>/dev/null" tell process appName
set screencaptureCmd to screencaptureCmd & " -l" & windowID set winPosition to position of window 1
on error set winSize to size of window 1
-- Fallback to full screen if we can't get window ID end tell
my logVerbose("Could not get window ID, falling back to full screen capture") end tell
set x to item 1 of winPosition
set y to item 2 of winPosition
set w to item 1 of winSize
set h to item 2 of winSize
-- Use -R flag to capture a specific rectangle
set screencaptureCmd to screencaptureCmd & " -R" & x & "," & y & "," & w & "," & h
my logVerbose("Capturing window bounds for " & appName & ": " & x & "," & y & "," & w & "," & h)
on error errMsg
-- Fallback to full screen if we can't get window bounds
my logVerbose("Could not get window bounds for " & appName & ", error: " & errMsg)
my logVerbose("Falling back to full screen capture")
end try end try
end if end if
@ -852,6 +865,77 @@ on captureScreenshot(outputPath, captureMode, appName)
end try end try
end captureScreenshot end captureScreenshot
on captureWindowByIndex(outputPath, appName, winIndex)
my logVerbose("Capturing window " & winIndex & " of " & appName & " to: " & outputPath)
-- Ensure output directory exists
set outputDir to do shell script "dirname " & quoted form of outputPath
if not my ensureDirectoryExists(outputDir) then
return my formatErrorMessage("Directory Error", "Could not create output directory: " & outputDir, "directory creation")
end if
-- Wait for capture delay
delay captureDelay
-- Determine screenshot format
set fileExt to my getFileExtension(outputPath)
if fileExt is "" then
set fileExt to defaultScreenshotFormat
set outputPath to outputPath & "." & fileExt
end if
-- Build screencapture command
set screencaptureCmd to "screencapture -x"
-- Get window bounds for specific window
try
tell application "System Events"
tell process appName
set winPosition to position of window winIndex
set winSize to size of window winIndex
end tell
end tell
set x to item 1 of winPosition
set y to item 2 of winPosition
set w to item 1 of winSize
set h to item 2 of winSize
-- Use -R flag to capture a specific rectangle
set screencaptureCmd to screencaptureCmd & " -R" & x & "," & y & "," & w & "," & h
my logVerbose("Capturing window " & winIndex & " bounds: " & x & "," & y & "," & w & "," & h)
on error errMsg
-- Fallback to full screen if we can't get window bounds
my logVerbose("Could not get bounds for window " & winIndex & ", error: " & errMsg)
return my formatErrorMessage("Window Error", "Could not get bounds for window " & winIndex & " of " & appName, "window bounds")
end try
-- Add format flag if not PNG (default)
if fileExt is not "png" then
set screencaptureCmd to screencaptureCmd & " -t " & fileExt
end if
-- Add output path
set screencaptureCmd to screencaptureCmd & " " & quoted form of outputPath
-- Capture screenshot
try
my logVerbose("Running: " & screencaptureCmd)
do shell script screencaptureCmd
-- Verify file was created
try
do shell script "test -f " & quoted form of outputPath
return outputPath
on error
return my formatErrorMessage("Capture Error", "Screenshot file was not created at: " & outputPath, "file verification")
end try
on error errMsg
return my formatErrorMessage("Capture Error", "Failed to capture window: " & errMsg, "screencapture")
end try
end captureWindowByIndex
on captureMultipleWindows(appName, baseOutputPath) on captureMultipleWindows(appName, baseOutputPath)
-- Get detailed window status first -- Get detailed window status first
set windowStatus to my getAppWindowStatus(appName) set windowStatus to my getAppWindowStatus(appName)
@ -915,8 +999,8 @@ on captureMultipleWindows(appName, baseOutputPath)
my logVerbose("Could not focus window " & winIndex & ", continuing anyway") my logVerbose("Could not focus window " & winIndex & ", continuing anyway")
end try end try
-- Capture the frontmost window -- Capture the specific window using a custom method
set captureResult to my captureScreenshot(windowOutputPath, "window", appName) set captureResult to my captureWindowByIndex(windowOutputPath, appName, winIndex)
if captureResult starts with scriptInfoPrefix then if captureResult starts with scriptInfoPrefix then
-- Error occurred, but continue with other windows -- Error occurred, but continue with other windows
my logVerbose("Failed to capture window " & winIndex & ": " & captureResult) my logVerbose("Failed to capture window " & winIndex & ": " & captureResult)