From 163ee1d75a62e3653b7585447e6502c2b3da355f Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Wed, 13 Dec 2023 14:41:27 -0600 Subject: [PATCH] macos: special case handling of some control keys Some control key combinations must be handled specially by Ghostty to prevent undesirable behavior at the OS level. For now, this includes only Ctrl-/, which makes a "beep" sound when processed by AppKit. It is unclear why this beep occurs and no answer was found after extensive searching. This solution is inspired by iTerm2, which also handles certain control key combinations (including C-/) manually before passing them on to Cocoa/AppKit. --- macos/Sources/Ghostty/SurfaceView.swift | 43 ++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/macos/Sources/Ghostty/SurfaceView.swift b/macos/Sources/Ghostty/SurfaceView.swift index e83f08cc3..943f308f0 100644 --- a/macos/Sources/Ghostty/SurfaceView.swift +++ b/macos/Sources/Ghostty/SurfaceView.swift @@ -783,7 +783,7 @@ extension Ghostty { let action = event.isARepeat ? GHOSTTY_ACTION_REPEAT : GHOSTTY_ACTION_PRESS - // By setting this to non-nil, we note that we'rein a keyDown event. From here, + // By setting this to non-nil, we note that we're in a keyDown event. From here, // we call interpretKeyEvents so that we can handle complex input such as Korean // language. keyTextAccumulator = [] @@ -825,6 +825,47 @@ extension Ghostty { keyAction(GHOSTTY_ACTION_RELEASE, event: event) } + /// Special case handling for some control keys + override func performKeyEquivalent(with event: NSEvent) -> Bool { + // Only process keys when Control is the only modifier + if (!event.modifierFlags.contains(.control) || + !event.modifierFlags.isDisjoint(with: [.shift, .command, .option])) { + return false + } + + // Only process key down events + if (event.type != .keyDown) { + return false + } + + let equivalent: String? + switch (event.charactersIgnoringModifiers) { + case "/": + // Treat C-/ as C-_ + equivalent = "_" + default: + equivalent = nil + } + + guard let equivalent else { return false } + + let newEvent = NSEvent.keyEvent( + with: .keyDown, + location: event.locationInWindow, + modifierFlags: .control, + timestamp: event.timestamp, + windowNumber: event.windowNumber, + context: nil, + characters: equivalent, + charactersIgnoringModifiers: equivalent, + isARepeat: event.isARepeat, + keyCode: event.keyCode + ) + + self.keyDown(with: newEvent!) + return true + } + override func flagsChanged(with event: NSEvent) { let mod: UInt32; switch (event.keyCode) {