Skip to content

Commit cbe375c

Browse files
committed
Route browser content keys around performKeyEquivalent
1 parent eca313f commit cbe375c

2 files changed

Lines changed: 100 additions & 5 deletions

File tree

Sources/AppDelegate.swift

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1524,6 +1524,25 @@ func shouldDirectRouteBrowserFirstResponderKeyDown(
15241524
return firstResponder != nil
15251525
}
15261526

1527+
enum BrowserDirectKeyRoutingStrategy: Equatable {
1528+
case keyDown
1529+
case menuOrAppShortcutThenKeyDown
1530+
case deferToOriginalPerformKeyEquivalent
1531+
}
1532+
1533+
func browserDirectKeyRoutingStrategy(for event: NSEvent) -> BrowserDirectKeyRoutingStrategy {
1534+
let flags = event.modifierFlags.intersection(.deviceIndependentFlagsMask)
1535+
guard flags.contains(.command) else {
1536+
return .keyDown
1537+
}
1538+
1539+
guard shouldRouteCommandEquivalentDirectlyToMainMenu(event) else {
1540+
return .deferToOriginalPerformKeyEquivalent
1541+
}
1542+
1543+
return .menuOrAppShortcutThenKeyDown
1544+
}
1545+
15271546
func shouldToggleMainWindowFullScreenForCommandControlFShortcut(
15281547
flags: NSEvent.ModifierFlags,
15291548
chars: String,
@@ -12878,18 +12897,34 @@ private extension NSWindow {
1287812897
return false
1287912898
}
1288012899

12881-
if browserRoute.webView.performKeyEquivalent(with: event) {
12900+
switch browserDirectKeyRoutingStrategy(for: event) {
12901+
case .deferToOriginalPerformKeyEquivalent:
12902+
return false
12903+
12904+
case .menuOrAppShortcutThenKeyDown:
12905+
if let mainMenu = NSApp.mainMenu,
12906+
mainMenu.performKeyEquivalent(with: event) {
1288212907
#if DEBUG
12883-
let targetType = String(describing: type(of: browserRoute.webView))
12884-
dlog("window.browserKeyDirect route=performKeyEquivalent target=\(targetType)")
12908+
dlog("window.browserKeyDirect route=mainMenu")
1288512909
#endif
12886-
return true
12910+
return true
12911+
}
12912+
12913+
if AppDelegate.shared?.handleBrowserSurfaceKeyEquivalent(event) == true {
12914+
#if DEBUG
12915+
dlog("window.browserKeyDirect route=appShortcut")
12916+
#endif
12917+
return true
12918+
}
12919+
12920+
case .keyDown:
12921+
break
1288712922
}
1288812923

1288912924
if invokedFromPerformKeyEquivalent {
1289012925
if cmuxBrowserKeyDownForwardingDepth > 0 {
1289112926
#if DEBUG
12892-
dlog("window.browserKeyDirect route=performKeyEquivalentReentry")
12927+
dlog("window.browserKeyDirect route=keyDownReentry")
1289312928
#endif
1289412929
return false
1289512930
}

cmuxTests/BrowserConfigTests.swift

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2596,6 +2596,66 @@ final class BrowserDirectKeyDownRoutingTests: XCTestCase {
25962596
)
25972597
)
25982598
}
2599+
2600+
func testNonCommandBrowserKeysGoStraightToKeyDown() {
2601+
let event = makeKeyDownEvent(
2602+
characters: String(UnicodeScalar(NSDownArrowFunctionKey)!),
2603+
modifiers: [],
2604+
keyCode: 125
2605+
)
2606+
2607+
XCTAssertEqual(browserDirectKeyRoutingStrategy(for: event), .keyDown)
2608+
}
2609+
2610+
func testCommandShiftArrowFallsBackToBrowserKeyDownWhenNoShortcutConsumesIt() {
2611+
let event = makeKeyDownEvent(
2612+
characters: String(UnicodeScalar(NSDownArrowFunctionKey)!),
2613+
modifiers: [.command, .shift],
2614+
keyCode: 125
2615+
)
2616+
2617+
XCTAssertEqual(
2618+
browserDirectKeyRoutingStrategy(for: event),
2619+
.menuOrAppShortcutThenKeyDown
2620+
)
2621+
}
2622+
2623+
func testCommandBacktickDefersToOriginalPerformKeyEquivalent() {
2624+
let event = makeKeyDownEvent(
2625+
characters: "`",
2626+
modifiers: [.command],
2627+
keyCode: 50
2628+
)
2629+
2630+
XCTAssertEqual(
2631+
browserDirectKeyRoutingStrategy(for: event),
2632+
.deferToOriginalPerformKeyEquivalent
2633+
)
2634+
}
2635+
2636+
private func makeKeyDownEvent(
2637+
characters: String,
2638+
modifiers: NSEvent.ModifierFlags,
2639+
keyCode: UInt16
2640+
) -> NSEvent {
2641+
guard let event = NSEvent.keyEvent(
2642+
with: .keyDown,
2643+
location: .zero,
2644+
modifierFlags: modifiers,
2645+
timestamp: ProcessInfo.processInfo.systemUptime,
2646+
windowNumber: 0,
2647+
context: nil,
2648+
characters: characters,
2649+
charactersIgnoringModifiers: characters,
2650+
isARepeat: false,
2651+
keyCode: keyCode
2652+
) else {
2653+
XCTFail("Failed to create keyDown event for routing strategy test")
2654+
fatalError("Failed to create keyDown event")
2655+
}
2656+
2657+
return event
2658+
}
25992659
}
26002660

26012661
final class BrowserZoomShortcutActionTests: XCTestCase {

0 commit comments

Comments
 (0)