This commit is contained in:
austinpower1258 2026-02-24 13:54:52 -08:00
parent 2da5070782
commit 5dc2d8d800
2 changed files with 73 additions and 0 deletions

View file

@ -286,6 +286,14 @@ func browserOmnibarShouldSubmitOnReturn(flags: NSEvent.ModifierFlags) -> Bool {
return normalizedFlags == [] || normalizedFlags == [.shift]
}
func shouldDispatchBrowserReturnViaFirstResponderKeyDown(
keyCode: UInt16,
firstResponderIsBrowser: Bool
) -> Bool {
guard firstResponderIsBrowser else { return false }
return keyCode == 36 || keyCode == 76
}
func commandPaletteSelectionDeltaForKeyboardNavigation(
flags: NSEvent.ModifierFlags,
chars: String,
@ -5279,6 +5287,7 @@ enum MenuBarIconRenderer {
private var cmuxFirstResponderGuardCurrentEventOverride: NSEvent?
private var cmuxFirstResponderGuardHitViewOverride: NSView?
#endif
private var cmuxBrowserReturnForwardingDepth = 0
private extension NSWindow {
@objc func cmux_makeFirstResponder(_ responder: NSResponder?) -> Bool {
@ -5396,6 +5405,7 @@ private extension NSWindow {
// (handleCustomShortcut) already handles app-level shortcuts, and anything
// remaining should be menu items.
let firstResponderGhosttyView = cmuxOwningGhosttyView(for: self.firstResponder)
let firstResponderWebView = self.firstResponder.flatMap { Self.cmuxOwningWebView(for: $0) }
if let ghosttyView = firstResponderGhosttyView {
// If the IME is composing, don't intercept key events let them flow
// through normal AppKit event dispatch so the input method can process them.
@ -5429,6 +5439,31 @@ private extension NSWindow {
}
}
// Web forms rely on Return/Enter flowing through keyDown. If the original
// NSWindow.performKeyEquivalent consumes Enter first, submission never reaches
// WebKit. Route Return/Enter directly to the current first responder and
// mark handled to avoid the AppKit alert sound path.
if shouldDispatchBrowserReturnViaFirstResponderKeyDown(
keyCode: event.keyCode,
firstResponderIsBrowser: firstResponderWebView != nil
) {
// Forwarding keyDown can re-enter performKeyEquivalent in WebKit/AppKit internals.
// On re-entry, fall back to normal dispatch to avoid an infinite loop.
if cmuxBrowserReturnForwardingDepth > 0 {
#if DEBUG
dlog(" → browser Return/Enter reentry; using normal dispatch")
#endif
return false
}
cmuxBrowserReturnForwardingDepth += 1
defer { cmuxBrowserReturnForwardingDepth = max(0, cmuxBrowserReturnForwardingDepth - 1) }
#if DEBUG
dlog(" → browser Return/Enter routed to firstResponder.keyDown")
#endif
self.firstResponder?.keyDown(with: event)
return true
}
if AppDelegate.shared?.handleBrowserSurfaceKeyEquivalent(event) == true {
#if DEBUG
dlog(" → consumed by handleBrowserSurfaceKeyEquivalent")

View file

@ -1520,6 +1520,44 @@ final class BrowserOmnibarCommandNavigationTests: XCTestCase {
}
}
final class BrowserReturnKeyDownRoutingTests: XCTestCase {
func testRoutesForReturnWhenBrowserFirstResponder() {
XCTAssertTrue(
shouldDispatchBrowserReturnViaFirstResponderKeyDown(
keyCode: 36,
firstResponderIsBrowser: true
)
)
}
func testRoutesForKeypadEnterWhenBrowserFirstResponder() {
XCTAssertTrue(
shouldDispatchBrowserReturnViaFirstResponderKeyDown(
keyCode: 76,
firstResponderIsBrowser: true
)
)
}
func testDoesNotRouteForNonEnterKey() {
XCTAssertFalse(
shouldDispatchBrowserReturnViaFirstResponderKeyDown(
keyCode: 13,
firstResponderIsBrowser: true
)
)
}
func testDoesNotRouteWhenFirstResponderIsNotBrowser() {
XCTAssertFalse(
shouldDispatchBrowserReturnViaFirstResponderKeyDown(
keyCode: 36,
firstResponderIsBrowser: false
)
)
}
}
final class BrowserZoomShortcutActionTests: XCTestCase {
func testZoomInSupportsEqualsAndPlusVariants() {
XCTAssertEqual(