diff --git a/macos/Sources/Ghostty/SurfaceView_AppKit.swift b/macos/Sources/Ghostty/SurfaceView_AppKit.swift index c933eb9bf..a9ad39136 100644 --- a/macos/Sources/Ghostty/SurfaceView_AppKit.swift +++ b/macos/Sources/Ghostty/SurfaceView_AppKit.swift @@ -828,8 +828,28 @@ extension Ghostty { var handled: Bool = false if let list = keyTextAccumulator, list.count > 0 { handled = true - for text in list { - _ = keyAction(action, event: event, text: text) + + // This is a hack. libghostty on macOS treats ctrl input as not having + // text because some keyboard layouts generate bogus characters for + // ctrl+key. libghostty can't tell this is from an IM keyboard giving + // us direct values. So, we just remove control. + var modifierFlags = event.modifierFlags + modifierFlags.remove(.control) + if let keyTextEvent = NSEvent.keyEvent( + with: .keyDown, + location: event.locationInWindow, + modifierFlags: modifierFlags, + timestamp: event.timestamp, + windowNumber: event.windowNumber, + context: nil, + characters: event.characters ?? "", + charactersIgnoringModifiers: event.charactersIgnoringModifiers ?? "", + isARepeat: event.isARepeat, + keyCode: event.keyCode + ) { + for text in list { + _ = keyAction(action, event: keyTextEvent, text: text) + } } } diff --git a/src/apprt/embedded.zig b/src/apprt/embedded.zig index 50d1e90e4..44c4c5f20 100644 --- a/src/apprt/embedded.zig +++ b/src/apprt/embedded.zig @@ -199,6 +199,11 @@ pub const App = struct { // This logic only applies to macOS. if (comptime builtin.os.tag != .macos) break :event_text event.text; + // If we're in a preedit state then we allow it through. This + // allows ctrl sequences that affect IME to work. For example, + // Ctrl+H deletes a character with Japanese input. + if (event.composing) break :event_text event.text; + // If the modifiers are ONLY "control" then we never process // the event text because we want to do our own translation so // we can handle ctrl+c, ctrl+z, etc.