import AppKit import WebKit /// WKWebView tends to consume some Command-key equivalents (e.g. Cmd+N/Cmd+W), /// preventing the app menu/SwiftUI Commands from receiving them. Route menu /// key equivalents first so app-level shortcuts continue to work when WebKit is /// the first responder. final class CmuxWebView: WKWebView { override func performKeyEquivalent(with event: NSEvent) -> Bool { // Let the app menu handle key equivalents first (New Tab, Close Tab, tab switching, etc). if let menu = NSApp.mainMenu, menu.performKeyEquivalent(with: event) { return true } // Handle app-level shortcuts that are not menu-backed (for example split commands). // Without this, WebKit can consume Cmd-based shortcuts before the app monitor sees them. if AppDelegate.shared?.handleBrowserSurfaceKeyEquivalent(event) == true { return true } return super.performKeyEquivalent(with: event) } override func keyDown(with event: NSEvent) { // Some Cmd-based key paths in WebKit don't consistently invoke performKeyEquivalent. // Route them through the same app-level shortcut handler as a fallback. if event.modifierFlags.intersection(.deviceIndependentFlagsMask).contains(.command), AppDelegate.shared?.handleBrowserSurfaceKeyEquivalent(event) == true { return } super.keyDown(with: event) } // MARK: - Focus on click // The SwiftUI Color.clear overlay (.onTapGesture) that focuses panes can't receive // clicks when a WKWebView is underneath — AppKit delivers the click to the deepest // NSView (WKWebView), not to sibling SwiftUI overlays. Notify the panel system so // bonsplit focus tracks which pane the user clicked in. override func mouseDown(with event: NSEvent) { NotificationCenter.default.post(name: .webViewDidReceiveClick, object: self) super.mouseDown(with: event) } // MARK: - Drag-and-drop passthrough // WKWebView inherently calls registerForDraggedTypes with public.text (and others). // Bonsplit tab drags use NSString (public.utf8-plain-text) which conforms to public.text, // so AppKit's view-hierarchy-based drag routing delivers the session to WKWebView instead // of SwiftUI's sibling .onDrop overlays. Rejecting in draggingEntered doesn't help because // AppKit only bubbles up through superviews, not siblings. // // Fix: prevent WKWebView from registering as a drag destination entirely. AppKit won't // route drags here, so they reach the SwiftUI overlay drop zones as intended. override func registerForDraggedTypes(_ newTypes: [NSPasteboard.PasteboardType]) { // No-op: suppress WKWebView's automatic drag type registration. } override func willOpenMenu(_ menu: NSMenu, with event: NSEvent) { super.willOpenMenu(menu, with: event) for item in menu.items { // Rename "Open Link in New Window" to "Open Link in New Tab". // The UIDelegate's createWebViewWith already handles the action // by opening the link as a new surface in the same pane. if item.identifier?.rawValue == "WKMenuItemIdentifierOpenLinkInNewWindow" || item.title.contains("Open Link in New Window") { item.title = "Open Link in New Tab" } } } }