Skip to content

Preserve cached keyboard geometry across rotation - #6

Open
robmaceachern wants to merge 2 commits into
mainfrom
robmaceachern/keyboard-frame-coordinate-space
Open

robmaceachern wants to merge 2 commits into
mainfrom
robmaceachern/keyboard-frame-coordinate-space

Conversation

@robmaceachern

@robmaceachern robmaceachern commented Oct 2, 2026 •

Copy link
Copy Markdown
Member
🤖 Agent details

Contribution: Implementation and PR description

Agent: Codex

Session: Local Codex session

Generated by the explain-like-im-engineer skill.

A keyboard that has already disappeared can produce a false overlap after an iPad rotates. KeyboardObserver saves the notification's raw rectangle, then later converts it using the screen's current orientation. For example, a hidden landscape keyboard at (0,820,1180,422) becomes a 360-point overlap in an 820×1180 portrait viewport.

Store the rectangle in the screen's fixed coordinate space when receiving the notification, then convert that saved position into the requested view. Preserve the floating-keyboard classification from the same delivery-time geometry, compare both raw and normalized geometry plus screen identity when suppressing duplicate callbacks, and ignore keyboards on another display.

This was reproduced with an actual UIKit software keyboard in a full-screen scene app on an iPadOS 26.5 simulator: show in landscape, dismiss, then rotate to portrait. No keyboard frame notification arrived across the recorded rotation interval; UIKit's keyboard layout guide showed only the bottom safe area. Converting the hidden frame at receipt placed it entirely outside the physical screen. This follows Apple's guidance for persisted screen coordinates.

Validation: the complete existing observer suite plus regressions for cached hidden/visible geometry, floating classification, meaningful duplicate detection, foreign displays, and notifications without a screen. The coordinate regressions use UIKit coordinate conversions with a controlled rotating screen fixture; the recorded UIKit sequence above independently establishes the sequence occurs in an app. All 20 tests pass on iOS 26.5. Running the final regressions against the original implementation produced six assertion failures across five cases. A Dashboard scene build compiles with this exact source and the companion Market reader fix. With Home keyboard avoidance enabled, mock authentication, Home/Me navigation, and background/foreground transitions leave its floating button at the expected bottom position. The full sequence also passes in the fixed scene application: show and dismiss the software keyboard in landscape, then rotate to portrait upside-down, which the app supports on iPad. The raw hide frame remains cached and no new keyboard notification arrives during rotation, while the saved fixed-space rectangle stays offscreen. Home's keyboard-aware button returns to its expected bottom position.

Notifications without a screen use the main display at receipt, covering older iOS notifications and the existing simulator fallback. This retains the public API and its nil result for views without a window or an observer with no notification.

The CI test simulator is updated to the runner's available iPad (A16), iOS 26.2, matching the selected Xcode. The previous job stopped before executing tests because iOS 18.6 and its configured iPad were absent. The corrected validation workflow passes: all 20 tests executed with zero failures, the demo app builds, and formatting passes.


This response was drafted with AI assistance.

@github-advanced-security

Copy link
Copy Markdown

You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool.

What Enabling Code Scanning Means:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

Convert notification frames into fixed screen coordinates at receipt.
Keep floating classification tied to the same geometry, preserve existing
changed-frame callbacks, and ignore keyboards on another display.

Cover the real hide-in-landscape then rotate sequence with UIKit
coordinate-space regressions, alongside callback and fallback behavior.

---
*This response was drafted with AI assistance.*
The current macOS runner no longer includes iOS 18.6 or an iPad
10th generation simulator. Run the suite on its available iPad A16
with iOS 26.2, matching the selected Xcode version.

---
*This response was drafted with AI assistance.*
@robmaceachern
robmaceachern force-pushed the robmaceachern/keyboard-frame-coordinate-space branch from 5a0dee9 to 6a0c925 Compare October 2, 2026 04:55
@johnnewman-square johnnewman-square self-assigned this Oct 6, 2026
Comment on lines +309 to +310
isKeyboardFloating = endingFrame.maxY < frameScreen.bounds.maxY
&& endingFrame.width < frameScreen.bounds.width / 2

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

+1 to moving this into the notification extension.

Comment on lines +161 to +163
guard notification.frameScreen == window.screen else {
return .nonOverlapping
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

👍

@robmaceachern
robmaceachern marked this pull request as ready for review October 6, 2026 21:57
@robmaceachern
robmaceachern requested a review from a team as a code owner October 6, 2026 21:57
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.

3 participants