From f93eb0b27fa68c091d03ae6a8bf4021600caf7b2 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 2 Mar 2025 13:49:08 -0800 Subject: [PATCH] input: legacy encoding never encodes text for command mods on macOS Fixes #5929 Replaces #5984 On macOS, native applications typically never encode any text for key events that use the command key. This is because the command key is used for key equivalents and "commands" and should not be used for text input. This can be verified with apps like TextEdit but also terminals like Terminal.app officially but also iTerm2 unofficially. Anything such as `Cmd+b` or `Cmd+Shift+b` will not produce any text input. Cross-platform terminals generally don't follow this, for example Kitty performs CSI-u encoding and Alacritty and WezTerm encode the text as-is (i.e. `Cmd+b` will produce `b`). On Linux, the super key (command-equivalent) does produce text input. For example, `Super+b` will produce `b` in Gnome Console, Foot, and all the cross-platform terminals mentioned above. In the interest of matching the behavior of native macOS applications, we should not encode text for command key events on macOS. We continue to encode text for the super key on non-macOS platforms. --- src/input/KeyEncoder.zig | 46 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/input/KeyEncoder.zig b/src/input/KeyEncoder.zig index 2e7935214..c009fbe0d 100644 --- a/src/input/KeyEncoder.zig +++ b/src/input/KeyEncoder.zig @@ -35,6 +35,7 @@ pub fn encode( self: *const KeyEncoder, buf: []u8, ) ![]const u8 { + // log.warn("KEYENCODER self={}", .{self.j}); if (self.kitty_flags.int() != 0) return try self.kitty(buf); return try self.legacy(buf); } @@ -413,6 +414,19 @@ fn legacy( return try std.fmt.bufPrint(buf, "\x1B{c}", .{byte}); } + // If we are on macOS, command+keys do not encode text. It isn't + // typical for command+keys on macOS to ever encode text. They + // don't in native text inputs (i.e. TextEdit) and they also don't + // in other native terminals (Terminal.app officially but also + // iTerm2). + // + // For Linux, we continue to encode text because it is typical. + // For example on Gnome Console Super+b will encode a "b" character + // with legacy encoding. + if ((comptime builtin.os.tag == .macos) and all_mods.super) { + return ""; + } + return try copyToBuf(buf, utf8); } @@ -2163,6 +2177,38 @@ test "legacy: hu layout ctrl+ő sends proper codepoint" { try testing.expectEqualStrings("[337;5u", actual[1..]); } +test "legacy: super-only on macOS with text" { + if (comptime builtin.os.tag != .macos) return error.SkipZigTest; + + var buf: [128]u8 = undefined; + var enc: KeyEncoder = .{ + .event = .{ + .key = .b, + .utf8 = "b", + .mods = .{ .super = true }, + }, + }; + + const actual = try enc.legacy(&buf); + try testing.expectEqualStrings("", actual); +} + +test "legacy: super and other mods on macOS with text" { + if (comptime builtin.os.tag != .macos) return error.SkipZigTest; + + var buf: [128]u8 = undefined; + var enc: KeyEncoder = .{ + .event = .{ + .key = .b, + .utf8 = "B", + .mods = .{ .super = true, .shift = true }, + }, + }; + + const actual = try enc.legacy(&buf); + try testing.expectEqualStrings("", actual); +} + test "ctrlseq: normal ctrl c" { const seq = ctrlSeq(.invalid, "c", 'c', .{ .ctrl = true }); try testing.expectEqual(@as(u8, 0x03), seq.?);