diff --git a/src/Surface.zig b/src/Surface.zig index 1dc10fb27..9485d4b9d 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -1833,6 +1833,22 @@ pub fn keyCallback( return .consumed; } +pub fn isBindingMaskedByKittyDisambiguate( + self: *Surface, + action: input.Binding.Action, +) bool { + switch (action) { + .esc_unless_kitty_disambiguate, + .text_unless_kitty_disambiguate => { + if (self.io.terminal.screen.kitty_keyboard.current().disambiguate) { + return true; + } + }, + else => {}, + } + return false; +} + /// Maybe handles a binding for a given event and if so returns the effect. /// Returns null if the event is not handled in any way and processing should /// continue. @@ -1916,6 +1932,10 @@ fn maybeHandleBinding( }; const action = leaf.action; + if (self.isBindingMaskedByKittyDisambiguate(action)) { + return null; + } + // consumed determines if the input is consumed or if we continue // encoding the key (if we have a key to encode). const consumed = consumed: { @@ -3826,14 +3846,14 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool } switch (action.scoped(.surface).?) { - .csi, .esc => |data| { + .csi, .esc_unless_kitty_disambiguate => |data| { // We need to send the CSI/ESC sequence as a single write request. // If you split it across two then the shell can interpret it // as two literals. var buf: [128]u8 = undefined; const full_data = switch (action) { .csi => try std.fmt.bufPrint(&buf, "\x1b[{s}", .{data}), - .esc => try std.fmt.bufPrint(&buf, "\x1b{s}", .{data}), + .esc_unless_kitty_disambiguate => try std.fmt.bufPrint(&buf, "\x1b{s}", .{data}), else => unreachable, }; self.io.queueMessage(try termio.Message.writeReq( @@ -3851,7 +3871,7 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool } }, - .text => |data| { + .text_unless_kitty_disambiguate => |data| { // For text we always allocate just because its easier to // handle all cases that way. const buf = try self.alloc.alloc(u8, data.len); diff --git a/src/apprt/embedded.zig b/src/apprt/embedded.zig index 10d09988d..fabd6fab1 100644 --- a/src/apprt/embedded.zig +++ b/src/apprt/embedded.zig @@ -1825,6 +1825,10 @@ pub const CAPI = struct { return false; }; + if (ptr.isBindingMaskedByKittyDisambiguate(action)) { + return false; + } + _ = ptr.core_surface.performBindingAction(action) catch |err| { log.err("error performing binding action action={} err={}", .{ action, err }); return false; diff --git a/src/config/Config.zig b/src/config/Config.zig index cbeafdd1c..40bd314b7 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -2715,27 +2715,27 @@ pub fn default(alloc_gpa: Allocator) Allocator.Error!Config { try result.keybind.set.put( alloc, .{ .key = .{ .translated = .right }, .mods = .{ .super = true } }, - .{ .text = "\\x05" }, + .{ .text_unless_kitty_disambiguate = "\\x05" }, ); try result.keybind.set.put( alloc, .{ .key = .{ .translated = .left }, .mods = .{ .super = true } }, - .{ .text = "\\x01" }, + .{ .text_unless_kitty_disambiguate = "\\x01" }, ); try result.keybind.set.put( alloc, .{ .key = .{ .translated = .backspace }, .mods = .{ .super = true } }, - .{ .esc = "\x15" }, + .{ .esc_unless_kitty_disambiguate = "\x15" }, ); try result.keybind.set.put( alloc, .{ .key = .{ .translated = .left }, .mods = .{ .alt = true } }, - .{ .esc = "b" }, + .{ .esc_unless_kitty_disambiguate = "b" }, ); try result.keybind.set.put( alloc, .{ .key = .{ .translated = .right }, .mods = .{ .alt = true } }, - .{ .esc = "f" }, + .{ .esc_unless_kitty_disambiguate = "f" }, ); } diff --git a/src/input/Binding.zig b/src/input/Binding.zig index e0ad6c571..3ecff992a 100644 --- a/src/input/Binding.zig +++ b/src/input/Binding.zig @@ -233,13 +233,14 @@ pub const Action = union(enum) { /// CSI header (`ESC [` or `\x1b[`). csi: []const u8, - /// Send an `ESC` sequence. - esc: []const u8, + /// Unless kitty disambiguate is active, send an `ESC` sequence. + esc_unless_kitty_disambiguate: []const u8, - // Send the given text. Uses Zig string literal syntax. This is currently - // not validated. If the text is invalid (i.e. contains an invalid escape - // sequence), the error will currently only show up in logs. - text: []const u8, + // Unless kitty disambiguate is active, send the given text. Uses Zig + // string literal syntax. This is currently not validated. If the text + // is invalid (i.e. contains an invalid escape sequence), the error will + // currently only show up in logs. + text_unless_kitty_disambiguate: []const u8, /// Send data to the pty depending on whether cursor key mode is enabled /// (`application`) or disabled (`normal`). @@ -702,8 +703,8 @@ pub const Action = union(enum) { // Obviously surface actions. .csi, - .esc, - .text, + .esc_unless_kitty_disambiguate, + .text_unless_kitty_disambiguate, .cursor_key, .reset, .copy_to_clipboard, @@ -1897,8 +1898,8 @@ test "parse: action with string" { // parameter { const binding = try parseSingle("a=esc:A"); - try testing.expect(binding.action == .esc); - try testing.expectEqualStrings("A", binding.action.esc); + try testing.expect(binding.action == .esc_unless_kitty_disambiguate); + try testing.expectEqualStrings("A", binding.action.esc_unless_kitty_disambiguate); } }