From dde1ae51bd66df534a16f330629b26b6c0b2f106 Mon Sep 17 00:00:00 2001 From: Bryan Lee <38807139+liby@users.noreply.github.com> Date: Sat, 4 Jan 2025 15:00:04 +0800 Subject: [PATCH] Handle `super+period` key combination on macOS Previously on macOS, `super+period` key combination was being blocked in `performKeyEquivalent` due to a control modifier check. This change removes that restriction to allow `super+period` and similar key combinations to be properly handled. Fixes #4540 --- .../Sources/Ghostty/SurfaceView_AppKit.swift | 88 +++++++++++-------- 1 file changed, 52 insertions(+), 36 deletions(-) diff --git a/macos/Sources/Ghostty/SurfaceView_AppKit.swift b/macos/Sources/Ghostty/SurfaceView_AppKit.swift index 2cac4a0dd..90f9238b2 100644 --- a/macos/Sources/Ghostty/SurfaceView_AppKit.swift +++ b/macos/Sources/Ghostty/SurfaceView_AppKit.swift @@ -810,49 +810,65 @@ extension Ghostty { return false } - // Only process keys when Control is active. All known issues we're - // resolving happen only in this scenario. This probably isn't fully robust - // but we can broaden the scope as we find more cases. - if (!event.modifierFlags.contains(.control)) { - return false - } + // First check if this is a special key combination we want to handle + // NOTE: We used to only process Control key combinations here as a defensive measure. + // This has been removed to support more key combinations (like super+period), + // but we need to be careful about potential conflicts with system shortcuts. + // Each key combination should be explicitly checked in the switch statement below. + let (shouldHandle, equivalent): (Bool, String?) = { + switch (event.charactersIgnoringModifiers) { + case "/": + // Treat C-/ as C-_. We do this because C-/ makes macOS make a beep + // sound and we don't like the beep sound. + if (event.modifierFlags.contains(.control) && + event.modifierFlags.isDisjoint(with: [.shift, .command, .option])) { + return (true, "_") + } - let equivalent: String - switch (event.charactersIgnoringModifiers) { - case "/": - // Treat C-/ as C-_. We do this because C-/ makes macOS make a beep - // sound and we don't like the beep sound. - if (!event.modifierFlags.contains(.control) || - !event.modifierFlags.isDisjoint(with: [.shift, .command, .option])) { - return false + case "\r": + // Pass C- through verbatim + // (prevent the default context menu equivalent) + if (event.modifierFlags.contains(.control)) { + return (true, "\r") + } + + case ".": + // Handle super+period + if (event.modifierFlags.contains(.command)) { + return (true, ".") + } + + default: + break } + return (false, nil) + }() - equivalent = "_" - - case "\r": - // Pass C- through verbatim - // (prevent the default context menu equivalent) - equivalent = "\r" - - default: - // Ignore other events + // If we don't handle this combination, return false + if (!shouldHandle) { return false } - let newEvent = NSEvent.keyEvent( - with: .keyDown, - location: event.locationInWindow, - modifierFlags: event.modifierFlags, - timestamp: event.timestamp, - windowNumber: event.windowNumber, - context: nil, - characters: equivalent, - charactersIgnoringModifiers: equivalent, - isARepeat: event.isARepeat, - keyCode: event.keyCode - ) + // Create a new event if we need to change the character + let finalEvent: NSEvent + if let eq = equivalent, eq != event.charactersIgnoringModifiers { + finalEvent = NSEvent.keyEvent( + with: .keyDown, + location: event.locationInWindow, + modifierFlags: event.modifierFlags, + timestamp: event.timestamp, + windowNumber: event.windowNumber, + context: nil, + characters: eq, + charactersIgnoringModifiers: eq, + isARepeat: event.isARepeat, + keyCode: event.keyCode + ) ?? event + } else { + finalEvent = event + } - self.keyDown(with: newEvent!) + self.keyDown(with: finalEvent) return true }