From b4d393fdcf6dc735cd48acc1ac31e8c43ce794d6 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 13 Nov 2023 13:50:00 -0800 Subject: [PATCH] input: process alt-prefix even if utf8 text doesn't exist --- src/input/KeyEncoder.zig | 102 ++++++++++++++++++++++++++------------- 1 file changed, 68 insertions(+), 34 deletions(-) diff --git a/src/input/KeyEncoder.zig b/src/input/KeyEncoder.zig index 39c39021d..9e1bc0bc4 100644 --- a/src/input/KeyEncoder.zig +++ b/src/input/KeyEncoder.zig @@ -223,9 +223,16 @@ fn legacy( return buf[0..1]; } - // If we have no UTF8 text then at this point there is nothing to do. + // If we have no UTF8 text then the only possibility is the + // alt-prefix handling of unshifted codepoints... so we process that. const utf8 = self.event.utf8; - if (utf8.len == 0) return ""; + if (utf8.len == 0) { + if (try self.legacyAltPrefix(binding_mods, all_mods)) |byte| { + return try std.fmt.bufPrint(buf, "\x1B{c}", .{byte}); + } + + return ""; + } // In modify other keys state 2, we send the CSI 27 sequence // for any char with a modifier. Ctrl sequences like Ctrl+a @@ -293,44 +300,55 @@ fn legacy( // If we have alt-pressed and alt-esc-prefix is enabled, then // we need to prefix the utf8 sequence with an esc. - if (binding_mods.alt and self.alt_esc_prefix) alt: { - const byte = byte: { - // On macOS, we only handle option like alt in certain circumstances. - // Otherwise, macOS does a unicode translation and we allow that to - // happen. - if (comptime builtin.target.isDarwin()) { - switch (self.macos_option_as_alt) { - .false => break :alt, - .left => if (all_mods.sides.alt == .right) break :alt, - .right => if (all_mods.sides.alt == .left) break :alt, - .true => {}, - } - - if (self.event.unshifted_codepoint > 0) { - if (std.math.cast(u8, self.event.unshifted_codepoint)) |byte| { - break :byte byte; - } - } - } - - // Otherwise, we require utf8 to already have the byte represented. - if (utf8.len == 1) { - if (std.math.cast(u8, utf8[0])) |byte| { - break :byte byte; - } - } - - // Else, we can't figure out the byte to alt-prefix so we - // exit this handling. - break :alt; - }; - + if (try self.legacyAltPrefix(binding_mods, all_mods)) |byte| { return try std.fmt.bufPrint(buf, "\x1B{c}", .{byte}); } return try copyToBuf(buf, utf8); } +fn legacyAltPrefix( + self: *const KeyEncoder, + binding_mods: key.Mods, + mods: key.Mods, +) !?u8 { + // This only takes effect with alt pressed + if (!binding_mods.alt or !self.alt_esc_prefix) return null; + + // On macOS, we only handle option like alt in certain + // circumstances. Otherwise, macOS does a unicode translation + // and we allow that to happen. + if (comptime builtin.target.isDarwin()) { + switch (self.macos_option_as_alt) { + .false => return null, + .left => if (mods.sides.alt == .right) return null, + .right => if (mods.sides.alt == .left) return null, + .true => {}, + } + + if (self.event.unshifted_codepoint > 0) { + if (std.math.cast( + u8, + self.event.unshifted_codepoint, + )) |byte| { + return byte; + } + } + } + + // Otherwise, we require utf8 to already have the byte represented. + const utf8 = self.event.utf8; + if (utf8.len == 1) { + if (std.math.cast(u8, utf8[0])) |byte| { + return byte; + } + } + + // Else, we can't figure out the byte to alt-prefix so we + // exit this handling. + return null; +} + /// A helper to memcpy a src value to a buffer and return the result. fn copyToBuf(buf: []u8, src: []const u8) ![]const u8 { if (src.len > buf.len) return error.OutOfMemory; @@ -1178,6 +1196,22 @@ test "legacy: alt+c" { try testing.expectEqualStrings("\x1Bc", actual); } +test "legacy: alt+e only unshifted" { + var buf: [128]u8 = undefined; + var enc: KeyEncoder = .{ + .event = .{ + .key = .e, + .unshifted_codepoint = 'e', + .mods = .{ .alt = true }, + }, + .alt_esc_prefix = true, + .macos_option_as_alt = .true, + }; + + const actual = try enc.legacy(&buf); + try testing.expectEqualStrings("\x1Be", actual); +} + test "legacy: alt+x macos" { if (comptime !builtin.target.isDarwin()) return error.SkipZigTest;