Skip to content

Conversation

@VincentStark
Copy link
Contributor

Summary

  • Fix screenshot tool capturing rotated images when simulator is in landscape orientation
  • The simctl screenshot command captures raw framebuffer in portrait regardless of device rotation
  • This PR adds orientation detection and automatic rotation correction

Problem

When taking screenshots with the simulator in landscape mode, the resulting images were incorrectly oriented - the content appeared rotated 90° within a portrait-shaped frame. This made the screenshots unusable for visual verification workflows.

Root cause: xcrun simctl io screenshot captures the raw framebuffer which is always in portrait orientation, regardless of the simulated device's actual rotation.

Solution

  1. Orientation Detection: After capturing the screenshot, detect the simulator window dimensions using CoreGraphics via Swift:

    CGWindowListCopyWindowInfo(opts, kCGNullWindowID)

    If window width > height, the simulator is in landscape mode.

  2. Rotation Correction: When landscape is detected, rotate the image +90° using sips --rotate 90 to correct the orientation.

  3. Graceful Degradation: If orientation detection or rotation fails, the tool continues and returns the original (unrotated) image rather than failing completely.

Testing

  • Added comprehensive unit tests for detectLandscapeMode() function
  • Added unit tests for rotateImage() function
  • Added integration tests for the full screenshot flow with landscape detection
  • Updated existing tests to account for the new orientation detection command
  • All 1143 tests passing

Test Plan

  • Run npm run lint - passes
  • Run npm run format:check - passes
  • Run npm test - all 1143 tests pass
  • Manual testing with iPhone simulator in both Landscape Left and Landscape Right orientations

🤖 Generated with Claude Code

The simctl screenshot command captures the raw framebuffer in portrait
orientation regardless of the device's actual rotation. When the simulator
is in landscape mode, this results in a rotated image.

This fix:
- Detects simulator window orientation using CoreGraphics via Swift
- Applies +90° rotation using sips when landscape mode is detected
- Handles edge cases gracefully (detection failure, rotation failure)

The orientation detection works by querying the Simulator window dimensions
via CGWindowListCopyWindowInfo and comparing width vs height.

Tested with both Landscape Left and Landscape Right orientations.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 26, 2026

Walkthrough

This change introduces landscape orientation detection and automatic image correction to the screenshot tool. Two new functions are added to detect landscape mode via window dimensions and rotate images using the sips command. The screenshot capture flow is enhanced to check orientation before optimisation; if landscape is detected, a +90° rotation is applied to the captured image. Test cases are updated to reflect the new three-step process: screenshot capture, orientation detection, then image optimisation. A changelog entry documents this landscape handling behaviour.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title directly and concisely describes the main change: fixing landscape screenshot orientation, which aligns with the primary objective of the PR.
Description check ✅ Passed The description comprehensively explains the problem, solution, and testing approach, all directly related to the landscape screenshot orientation fix in the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@CHANGELOG.md`:
- Line 24: Update the CHANGELOG entry for "Fix screenshot tool capturing rotated
images when simulator is in landscape orientation..." to include the external
contributor attribution and PR link per project changelog format: append " (PR
#<number>, @<github-username>)" or the project's required attribution template
to that line so it reads with the PR number and author; ensure the text still
mentions detection via window dimensions and +90° rotation and matches the
repository's changelog style.

In `@src/mcp/tools/ui-automation/screenshot.ts`:
- Around line 32-46: The window-detection Swift snippet
(WINDOW_DETECTION_SWIFT_CODE) currently picks the first "Simulator" window and
can pick the wrong device; update the Swift logic to also match the requested
simulatorId (or device name) against the window title (kCGWindowName) so it only
selects the window whose title contains the simulatorId/device identifier, and
apply the same change to the related detection code used in the other block
(lines ~52-75) so both detection paths filter by simulatorId/device name before
extracting Width/Height; reference the kCGWindowName/kCGWindowOwnerName keys and
the WINDOW_DETECTION_SWIFT_CODE constant when making this change.

- Add PR link and author attribution to CHANGELOG.md
- Fix multi-simulator detection by filtering window lookup by device name:
  - Add getDeviceNameForSimulatorId() to resolve simulator UUID to device name
  - Update getWindowDetectionSwiftCode() to filter by device name
  - Update detectLandscapeMode() to accept optional device name parameter
- Add TypeScript interfaces for simctl device list JSON response
- Update tests to account for new device name lookup command sequence

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@VincentStark
Copy link
Contributor Author

Addressed CodeRabbit Review Comments

1. CHANGELOG Attribution ✅

Added PR link and author attribution as suggested:

- Fixed screenshot tool capturing rotated images when simulator is in landscape orientation by detecting window dimensions and applying +90° rotation to correct the framebuffer capture. ([`#186`](https://github.com/cameroncooke/XcodeBuildMCP/pull/186) by [`@VincentStark`](https://github.com/VincentStark))

2. Multi-Simulator Window Detection ✅

Fixed the issue where the Swift window detection could pick up the wrong simulator when multiple are open. The implementation now:

  1. Resolves device name from UUID: New getDeviceNameForSimulatorId() function uses xcrun simctl list devices -j to look up the device name (e.g., "iPhone 16 Pro") from the simulator UUID.

  2. Filters window by device name: Updated getWindowDetectionSwiftCode() to filter by device name in the window title, ensuring we detect the correct simulator window even when multiple simulators are running.

  3. Falls back gracefully: If device name lookup fails, falls back to the previous behavior of matching any iPhone window.

All tests have been updated to account for the new device name lookup command in the sequence.

Bug 1: Fix fallback logic that hardcoded 'iPhone' for iPad simulators
- When device name lookup fails, skip orientation detection entirely
- This is safer than guessing, as we don't know if it's iPhone or iPad

Bug 2: Fix substring matching that could select wrong simulator
- Changed from n.contains(deviceName) to hasPrefix + boundary check
- Prevents "iPhone 15" from incorrectly matching "iPhone 15 Pro" window
- Window title format is "Device Name – iOS version" so check for space separator

Updated tests:
- Added device name parameter to all detectLandscapeMode tests
- Added test for "no device name provided" scenario
- Updated simulator tests to return valid device list JSON in mocks

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@cameroncooke
Copy link
Collaborator

@VincentStark Thanks for the contribution! Will merge once checks have passed.

@cameroncooke
Copy link
Collaborator

cameroncooke commented Jan 27, 2026

@VincentStark can you fix the typechecke errors: npm run typecheck

Add missing 'process' property to mock executor return values.
The CommandResponse type requires a process property, which was
missing from the custom mock executors introduced in the previous commit.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@VincentStark
Copy link
Contributor Author

@cameroncooke no problem! Pushed the fix, should be fine now.

@cameroncooke
Copy link
Collaborator

@VincentStark formatter checks are failing too, can you run npm run format see the CONTRIBUTING checklist.

@VincentStark
Copy link
Contributor Author

@cameroncooke sorry about that! Ran everything from CONTRIBUTING pre-commit checklist now, it passes, so should be good.

@cameroncooke cameroncooke merged commit d0a4fff into getsentry:main Jan 28, 2026
2 checks passed
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.

2 participants