macos: filter option in AppKit when option-as-alt set

Fixes #872

In #867 we fixed macos-option-as-alt, but unfortunately AppKit ALSO does
some translation so some behaviors were not working correctly.
Specifically, when you had macos-option-as-alt set, option+e would
properly send `esc+e` to the pty but it would ALSO set the dead key
state for "`" since AppKit was still translating the option key.

This commit introduces a function to strip alt when necessary from the
translation modifiers used at the AppKit layer, preventing this
behavior.
This commit is contained in:
Mitchell Hashimoto
2023-11-13 13:26:37 -08:00
parent a8e82b13ce
commit 5001e2c60c
5 changed files with 133 additions and 1 deletions

View File

@@ -725,12 +725,51 @@ extension Ghostty {
}
override func keyDown(with event: NSEvent) {
guard let surface = self.surface else {
self.interpretKeyEvents([event])
return
}
// We need to translate the mods (maybe) to handle configs such as option-as-alt
let translationModsGhostty = Ghostty.eventModifierFlags(
mods: ghostty_surface_key_translation_mods(
surface,
Ghostty.ghosttyMods(event.modifierFlags)
)
)
// There are hidden bits set in our event that matter for certain dead keys
// so we can't use translationModsGhostty directly. Instead, we just check
// for exact states and set them.
var translationMods = event.modifierFlags
for flag in [NSEvent.ModifierFlags.shift, .control, .option, .command] {
if (translationModsGhostty.contains(flag)) {
translationMods.insert(flag)
} else {
translationMods.remove(flag)
}
}
// Build a new NSEvent we use only for translation
let translationEvent = NSEvent.keyEvent(
with: event.type,
location: event.locationInWindow,
modifierFlags: translationMods,
timestamp: event.timestamp,
windowNumber: event.windowNumber,
context: nil,
characters: event.characters ?? "",
charactersIgnoringModifiers: event.charactersIgnoringModifiers ?? "",
isARepeat: event.isARepeat,
keyCode: event.keyCode
) ?? event
// By setting this to non-nil, we note that we'rein a keyDown event. From here,
// we call interpretKeyEvents so that we can handle complex input such as Korean
// language.
keyTextAccumulator = []
defer { keyTextAccumulator = nil }
self.interpretKeyEvents([event])
self.interpretKeyEvents([translationEvent])
let action = event.isARepeat ? GHOSTTY_ACTION_REPEAT : GHOSTTY_ACTION_PRESS