Filed as FB24092251.
On macOS 27.0 beta (26A5388g), clicking into any text input inside a WKWebView in
a Mac Catalyst app makes focus oscillate forever and typing does nothing. CPU pegs
at 100% while the editor is focused. The same binary works fine on macOS 26.
The DOM element never actually loses focus. Only the window does:
window focus -> activeElement=TEXTAREA.inputarea
JS focus -> activeElement=TEXTAREA.inputarea
window blur -> activeElement=TEXTAREA.inputarea <- window loses key status
JS blur -> activeElement=TEXTAREA.inputarea <- element did not
...repeats indefinitely...
Pausing during the loop shows why. Focusing the element sends WebKit into UIKit's
software-keyboard machinery, on a platform that has no software keyboard:
-[UIKeyboardSceneDelegate containerWindowForViewService:]
-[UIKeyboardSceneDelegate _setKeyWindowSceneInputViews:animationStyle:]
-[UIKeyboardSceneDelegate _reloadInputViewsForResponder:force:fromBecomeFirstResponder:]
-[UIResponder(UIResponderInputViewAdditions) reloadInputViews]
-[WKContentView(WKInteraction) _continueElementDidFocus:...]
-[WKContentView(WKInteraction) _elementDidFocus:...]
WebKit::WebPageProxy::elementDidFocus(...)
Building that container steals key status from the web view. First responder ends
up on the enclosing _UIHostingView, so key presses are delivered there and
immediately cancelled:
pressesBegan: [...], focusedItem: monacoEditor
firstResponder at keypress: _UIHostingView<...>
pressesCancelled: [...]
The catch: -becomeFirstResponder cannot be used to recover, because it is the
trigger. Calling it re-enters _elementDidFocus and re-arms the loop permanently.
So there is no app-side way back — the only API that reclaims the keyboard is the
one that breaks it.
Minimal repro is just a WKWebView in a UIViewRepresentable inside a SwiftUI
hierarchy, with any focusable . No Monaco needed.
Partial mitigation, if you hit this: do not echo focus/blur commands back at the
web view in response to its own focus events, and treat a blur where
document.hasFocus() is false but activeElement is unchanged as a window-level
blur rather than an editing-ended event. That stops the runaway loop and keeps
your focus state correct — but it does not restore typing.
Has anyone found a way to get first responder back to the web view without
calling -becomeFirstResponder? Or a way to stop the keyboard scene delegate
engaging on Catalyst in the first place?
If you can reproduce on 27 beta, please file a duplicate referencing FB24092251.
0
0
45