native macOS codings agent orchestrator
6
fork

Configure Feed

Select the types of activity you want to include in your feed.

Gate ghostty binding → main menu forwarding on a real item match (#259)

`⌘⇧,` (ghostty's `reload_config`) did nothing in Supacode because the
surface view forwarded every consumed ghostty binding to
`NSApp.mainMenu.performKeyEquivalent` wholesale, which can intercept
ghostty-only shortcuts. Now only forward when an item actually matches
key + modifier mask (with implicit-shift handling for uppercase
keyEquivalent).

Fixes #240.

authored by

Stefano Bertagno and committed by
GitHub
6c807c63 3af3a164

+27
+27
supacode/Infrastructure/Ghostty/GhosttySurfaceView.swift
··· 1021 1021 guard focused else { return false } 1022 1022 1023 1023 if let bindingFlags = bindingFlags(for: event, surface: surface) { 1024 + // Only forward to the main menu when the event actually matches one of our registered 1025 + // menu items. `NSMenu.performKeyEquivalent` can otherwise intercept Ghostty-only 1026 + // shortcuts (e.g. `⌘⇧,` → reload_config) via AppKit's built-in menu matching quirks. 1024 1027 if shouldAttemptMenu(for: bindingFlags), 1025 1028 let menu = NSApp.mainMenu, 1029 + Self.mainMenuHasMatchingItem(for: event, in: menu), 1026 1030 menu.performKeyEquivalent(with: event) 1027 1031 { 1028 1032 return true ··· 1213 1217 1214 1218 @IBAction func changeTitle(_ sender: Any?) { 1215 1219 performBindingAction("prompt_surface_title") 1220 + } 1221 + 1222 + /// Recursively walks the main menu looking for any item whose key equivalent and 1223 + /// modifier mask match `event` exactly. We require an exact modifier match so that a 1224 + /// shortcut like `⌘,` (Settings) doesn't eat `⌘⇧,` (Ghostty's `reload_config`). 1225 + /// 1226 + /// An uppercase `keyEquivalent` encodes shift implicitly (AppKit convention), so we 1227 + /// fold that into the item's effective mask before comparing. 1228 + private static func mainMenuHasMatchingItem(for event: NSEvent, in menu: NSMenu) -> Bool { 1229 + guard let characters = event.charactersIgnoringModifiers?.lowercased(), !characters.isEmpty else { return false } 1230 + let shortcutMask: NSEvent.ModifierFlags = [.shift, .control, .option, .command] 1231 + let eventModifiers = event.modifierFlags.intersection(shortcutMask) 1232 + for item in menu.items { 1233 + if let submenu = item.submenu, mainMenuHasMatchingItem(for: event, in: submenu) { return true } 1234 + guard !item.keyEquivalent.isEmpty else { continue } 1235 + let itemKey = item.keyEquivalent 1236 + guard itemKey.lowercased() == characters else { continue } 1237 + var itemMask = item.keyEquivalentModifierMask.intersection(shortcutMask) 1238 + if itemKey != itemKey.lowercased() { itemMask.insert(.shift) } 1239 + guard itemMask == eventModifiers else { continue } 1240 + return true 1241 + } 1242 + return false 1216 1243 } 1217 1244 1218 1245 private func shouldAttemptMenu(for flags: ghostty_binding_flags_e) -> Bool {