input: remove translated

pull/7320/head
Mitchell Hashimoto 2025-05-08 08:47:21 -07:00
parent 91d15c89bc
commit a3462dd2bd
No known key found for this signature in database
GPG Key ID: 523D5DC389D273BC
9 changed files with 481 additions and 570 deletions

3
NOTES.md Normal file
View File

@ -0,0 +1,3 @@
- key backwards compatibility, e.g. `grave_accent`
- `physical:` backwards compatibility?

View File

@ -4343,12 +4343,12 @@ pub const Keybinds = struct {
// keybinds for opening and reloading config // keybinds for opening and reloading config
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .comma }, .mods = inputpkg.ctrlOrSuper(.{ .shift = true }) }, .{ .key = .{ .unicode = ',' }, .mods = inputpkg.ctrlOrSuper(.{ .shift = true }) },
.{ .reload_config = {} }, .{ .reload_config = {} },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .comma }, .mods = inputpkg.ctrlOrSuper(.{}) }, .{ .key = .{ .unicode = ',' }, .mods = inputpkg.ctrlOrSuper(.{}) },
.{ .open_config = {} }, .{ .open_config = {} },
); );
@ -4362,12 +4362,12 @@ pub const Keybinds = struct {
if (!builtin.target.os.tag.isDarwin()) { if (!builtin.target.os.tag.isDarwin()) {
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .insert }, .mods = .{ .ctrl = true } }, .{ .key = .{ .physical = .insert }, .mods = .{ .ctrl = true } },
.{ .copy_to_clipboard = {} }, .{ .copy_to_clipboard = {} },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .insert }, .mods = .{ .shift = true } }, .{ .key = .{ .physical = .insert }, .mods = .{ .shift = true } },
.{ .paste_from_clipboard = {} }, .{ .paste_from_clipboard = {} },
); );
} }
@ -4381,12 +4381,12 @@ pub const Keybinds = struct {
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .c }, .mods = mods }, .{ .key = .{ .unicode = 'c' }, .mods = mods },
.{ .copy_to_clipboard = {} }, .{ .copy_to_clipboard = {} },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .v }, .mods = mods }, .{ .key = .{ .unicode = 'v' }, .mods = mods },
.{ .paste_from_clipboard = {} }, .{ .paste_from_clipboard = {} },
); );
} }
@ -4397,84 +4397,84 @@ pub const Keybinds = struct {
// set the expected keybind for the menu. // set the expected keybind for the menu.
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .plus }, .mods = inputpkg.ctrlOrSuper(.{}) }, .{ .key = .{ .unicode = '+' }, .mods = inputpkg.ctrlOrSuper(.{}) },
.{ .increase_font_size = 1 }, .{ .increase_font_size = 1 },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .equal }, .mods = inputpkg.ctrlOrSuper(.{}) }, .{ .key = .{ .physical = .equal }, .mods = inputpkg.ctrlOrSuper(.{}) },
.{ .increase_font_size = 1 }, .{ .increase_font_size = 1 },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .minus }, .mods = inputpkg.ctrlOrSuper(.{}) }, .{ .key = .{ .physical = .minus }, .mods = inputpkg.ctrlOrSuper(.{}) },
.{ .decrease_font_size = 1 }, .{ .decrease_font_size = 1 },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .zero }, .mods = inputpkg.ctrlOrSuper(.{}) }, .{ .key = .{ .physical = .digit_0 }, .mods = inputpkg.ctrlOrSuper(.{}) },
.{ .reset_font_size = {} }, .{ .reset_font_size = {} },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .j }, .mods = inputpkg.ctrlOrSuper(.{ .shift = true }) }, .{ .key = .{ .unicode = 'j' }, .mods = inputpkg.ctrlOrSuper(.{ .shift = true }) },
.{ .write_screen_file = .paste }, .{ .write_screen_file = .paste },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .j }, .mods = inputpkg.ctrlOrSuper(.{ .shift = true, .alt = true }) }, .{ .key = .{ .unicode = 'j' }, .mods = inputpkg.ctrlOrSuper(.{ .shift = true, .alt = true }) },
.{ .write_screen_file = .open }, .{ .write_screen_file = .open },
); );
// Expand Selection // Expand Selection
try self.set.putFlags( try self.set.putFlags(
alloc, alloc,
.{ .key = .{ .translated = .left }, .mods = .{ .shift = true } }, .{ .key = .{ .physical = .arrow_left }, .mods = .{ .shift = true } },
.{ .adjust_selection = .left }, .{ .adjust_selection = .left },
.{ .performable = true }, .{ .performable = true },
); );
try self.set.putFlags( try self.set.putFlags(
alloc, alloc,
.{ .key = .{ .translated = .right }, .mods = .{ .shift = true } }, .{ .key = .{ .physical = .arrow_right }, .mods = .{ .shift = true } },
.{ .adjust_selection = .right }, .{ .adjust_selection = .right },
.{ .performable = true }, .{ .performable = true },
); );
try self.set.putFlags( try self.set.putFlags(
alloc, alloc,
.{ .key = .{ .translated = .up }, .mods = .{ .shift = true } }, .{ .key = .{ .physical = .arrow_up }, .mods = .{ .shift = true } },
.{ .adjust_selection = .up }, .{ .adjust_selection = .up },
.{ .performable = true }, .{ .performable = true },
); );
try self.set.putFlags( try self.set.putFlags(
alloc, alloc,
.{ .key = .{ .translated = .down }, .mods = .{ .shift = true } }, .{ .key = .{ .physical = .arrow_down }, .mods = .{ .shift = true } },
.{ .adjust_selection = .down }, .{ .adjust_selection = .down },
.{ .performable = true }, .{ .performable = true },
); );
try self.set.putFlags( try self.set.putFlags(
alloc, alloc,
.{ .key = .{ .translated = .page_up }, .mods = .{ .shift = true } }, .{ .key = .{ .physical = .page_up }, .mods = .{ .shift = true } },
.{ .adjust_selection = .page_up }, .{ .adjust_selection = .page_up },
.{ .performable = true }, .{ .performable = true },
); );
try self.set.putFlags( try self.set.putFlags(
alloc, alloc,
.{ .key = .{ .translated = .page_down }, .mods = .{ .shift = true } }, .{ .key = .{ .physical = .page_down }, .mods = .{ .shift = true } },
.{ .adjust_selection = .page_down }, .{ .adjust_selection = .page_down },
.{ .performable = true }, .{ .performable = true },
); );
try self.set.putFlags( try self.set.putFlags(
alloc, alloc,
.{ .key = .{ .translated = .home }, .mods = .{ .shift = true } }, .{ .key = .{ .physical = .home }, .mods = .{ .shift = true } },
.{ .adjust_selection = .home }, .{ .adjust_selection = .home },
.{ .performable = true }, .{ .performable = true },
); );
try self.set.putFlags( try self.set.putFlags(
alloc, alloc,
.{ .key = .{ .translated = .end }, .mods = .{ .shift = true } }, .{ .key = .{ .physical = .end }, .mods = .{ .shift = true } },
.{ .adjust_selection = .end }, .{ .adjust_selection = .end },
.{ .performable = true }, .{ .performable = true },
); );
@ -4482,12 +4482,12 @@ pub const Keybinds = struct {
// Tabs common to all platforms // Tabs common to all platforms
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .tab }, .mods = .{ .ctrl = true, .shift = true } }, .{ .key = .{ .physical = .tab }, .mods = .{ .ctrl = true, .shift = true } },
.{ .previous_tab = {} }, .{ .previous_tab = {} },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .tab }, .mods = .{ .ctrl = true } }, .{ .key = .{ .physical = .tab }, .mods = .{ .ctrl = true } },
.{ .next_tab = {} }, .{ .next_tab = {} },
); );
@ -4495,174 +4495,174 @@ pub const Keybinds = struct {
if (comptime !builtin.target.os.tag.isDarwin()) { if (comptime !builtin.target.os.tag.isDarwin()) {
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .n }, .mods = .{ .ctrl = true, .shift = true } }, .{ .key = .{ .physical = .n }, .mods = .{ .ctrl = true, .shift = true } },
.{ .new_window = {} }, .{ .new_window = {} },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .w }, .mods = .{ .ctrl = true, .shift = true } }, .{ .key = .{ .physical = .w }, .mods = .{ .ctrl = true, .shift = true } },
.{ .close_surface = {} }, .{ .close_surface = {} },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .q }, .mods = .{ .ctrl = true, .shift = true } }, .{ .key = .{ .physical = .q }, .mods = .{ .ctrl = true, .shift = true } },
.{ .quit = {} }, .{ .quit = {} },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .f4 }, .mods = .{ .alt = true } }, .{ .key = .{ .physical = .f4 }, .mods = .{ .alt = true } },
.{ .close_window = {} }, .{ .close_window = {} },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .t }, .mods = .{ .ctrl = true, .shift = true } }, .{ .key = .{ .physical = .t }, .mods = .{ .ctrl = true, .shift = true } },
.{ .new_tab = {} }, .{ .new_tab = {} },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .w }, .mods = .{ .ctrl = true, .shift = true } }, .{ .key = .{ .physical = .w }, .mods = .{ .ctrl = true, .shift = true } },
.{ .close_tab = {} }, .{ .close_tab = {} },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .left }, .mods = .{ .ctrl = true, .shift = true } }, .{ .key = .{ .physical = .left }, .mods = .{ .ctrl = true, .shift = true } },
.{ .previous_tab = {} }, .{ .previous_tab = {} },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .right }, .mods = .{ .ctrl = true, .shift = true } }, .{ .key = .{ .physical = .right }, .mods = .{ .ctrl = true, .shift = true } },
.{ .next_tab = {} }, .{ .next_tab = {} },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .page_up }, .mods = .{ .ctrl = true } }, .{ .key = .{ .physical = .page_up }, .mods = .{ .ctrl = true } },
.{ .previous_tab = {} }, .{ .previous_tab = {} },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .page_down }, .mods = .{ .ctrl = true } }, .{ .key = .{ .physical = .page_down }, .mods = .{ .ctrl = true } },
.{ .next_tab = {} }, .{ .next_tab = {} },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .o }, .mods = .{ .ctrl = true, .shift = true } }, .{ .key = .{ .physical = .o }, .mods = .{ .ctrl = true, .shift = true } },
.{ .new_split = .right }, .{ .new_split = .right },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .e }, .mods = .{ .ctrl = true, .shift = true } }, .{ .key = .{ .physical = .e }, .mods = .{ .ctrl = true, .shift = true } },
.{ .new_split = .down }, .{ .new_split = .down },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .left_bracket }, .mods = .{ .ctrl = true, .super = true } }, .{ .key = .{ .physical = .bracket_left }, .mods = .{ .ctrl = true, .super = true } },
.{ .goto_split = .previous }, .{ .goto_split = .previous },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .right_bracket }, .mods = .{ .ctrl = true, .super = true } }, .{ .key = .{ .physical = .bracket_right }, .mods = .{ .ctrl = true, .super = true } },
.{ .goto_split = .next }, .{ .goto_split = .next },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .up }, .mods = .{ .ctrl = true, .alt = true } }, .{ .key = .{ .physical = .up }, .mods = .{ .ctrl = true, .alt = true } },
.{ .goto_split = .up }, .{ .goto_split = .up },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .down }, .mods = .{ .ctrl = true, .alt = true } }, .{ .key = .{ .physical = .down }, .mods = .{ .ctrl = true, .alt = true } },
.{ .goto_split = .down }, .{ .goto_split = .down },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .left }, .mods = .{ .ctrl = true, .alt = true } }, .{ .key = .{ .physical = .left }, .mods = .{ .ctrl = true, .alt = true } },
.{ .goto_split = .left }, .{ .goto_split = .left },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .right }, .mods = .{ .ctrl = true, .alt = true } }, .{ .key = .{ .physical = .right }, .mods = .{ .ctrl = true, .alt = true } },
.{ .goto_split = .right }, .{ .goto_split = .right },
); );
// Resizing splits // Resizing splits
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .up }, .mods = .{ .super = true, .ctrl = true, .shift = true } }, .{ .key = .{ .physical = .up }, .mods = .{ .super = true, .ctrl = true, .shift = true } },
.{ .resize_split = .{ .up, 10 } }, .{ .resize_split = .{ .up, 10 } },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .down }, .mods = .{ .super = true, .ctrl = true, .shift = true } }, .{ .key = .{ .physical = .down }, .mods = .{ .super = true, .ctrl = true, .shift = true } },
.{ .resize_split = .{ .down, 10 } }, .{ .resize_split = .{ .down, 10 } },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .left }, .mods = .{ .super = true, .ctrl = true, .shift = true } }, .{ .key = .{ .physical = .left }, .mods = .{ .super = true, .ctrl = true, .shift = true } },
.{ .resize_split = .{ .left, 10 } }, .{ .resize_split = .{ .left, 10 } },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .right }, .mods = .{ .super = true, .ctrl = true, .shift = true } }, .{ .key = .{ .physical = .right }, .mods = .{ .super = true, .ctrl = true, .shift = true } },
.{ .resize_split = .{ .right, 10 } }, .{ .resize_split = .{ .right, 10 } },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .plus }, .mods = .{ .super = true, .ctrl = true, .shift = true } }, .{ .key = .{ .physical = .plus }, .mods = .{ .super = true, .ctrl = true, .shift = true } },
.{ .equalize_splits = {} }, .{ .equalize_splits = {} },
); );
// Viewport scrolling // Viewport scrolling
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .home }, .mods = .{ .shift = true } }, .{ .key = .{ .physical = .home }, .mods = .{ .shift = true } },
.{ .scroll_to_top = {} }, .{ .scroll_to_top = {} },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .end }, .mods = .{ .shift = true } }, .{ .key = .{ .physical = .end }, .mods = .{ .shift = true } },
.{ .scroll_to_bottom = {} }, .{ .scroll_to_bottom = {} },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .page_up }, .mods = .{ .shift = true } }, .{ .key = .{ .physical = .page_up }, .mods = .{ .shift = true } },
.{ .scroll_page_up = {} }, .{ .scroll_page_up = {} },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .page_down }, .mods = .{ .shift = true } }, .{ .key = .{ .physical = .page_down }, .mods = .{ .shift = true } },
.{ .scroll_page_down = {} }, .{ .scroll_page_down = {} },
); );
// Semantic prompts // Semantic prompts
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .page_up }, .mods = .{ .shift = true, .ctrl = true } }, .{ .key = .{ .physical = .page_up }, .mods = .{ .shift = true, .ctrl = true } },
.{ .jump_to_prompt = -1 }, .{ .jump_to_prompt = -1 },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .page_down }, .mods = .{ .shift = true, .ctrl = true } }, .{ .key = .{ .physical = .page_down }, .mods = .{ .shift = true, .ctrl = true } },
.{ .jump_to_prompt = 1 }, .{ .jump_to_prompt = 1 },
); );
// Inspector, matching Chromium // Inspector, matching Chromium
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .i }, .mods = .{ .shift = true, .ctrl = true } }, .{ .key = .{ .physical = .i }, .mods = .{ .shift = true, .ctrl = true } },
.{ .inspector = .toggle }, .{ .inspector = .toggle },
); );
// Terminal // Terminal
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .a }, .mods = .{ .shift = true, .ctrl = true } }, .{ .key = .{ .physical = .a }, .mods = .{ .shift = true, .ctrl = true } },
.{ .select_all = {} }, .{ .select_all = {} },
); );
// Selection clipboard paste // Selection clipboard paste
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .insert }, .mods = .{ .shift = true } }, .{ .key = .{ .physical = .insert }, .mods = .{ .shift = true } },
.{ .paste_from_selection = {} }, .{ .paste_from_selection = {} },
); );
} }
@ -4675,23 +4675,14 @@ pub const Keybinds = struct {
.{ .alt = true }; .{ .alt = true };
// Cmd+N for goto tab N // Cmd+N for goto tab N
const start = @intFromEnum(inputpkg.Key.one); const start: u21 = '1';
const end = @intFromEnum(inputpkg.Key.eight); const end: u21 = '8';
var i: usize = start; var i: u21 = start;
while (i <= end) : (i += 1) { while (i <= end) : (i += 1) {
try self.set.put( try self.set.put(
alloc, alloc,
.{ .{
// On macOS, we use the physical key for tab changing so .key = .{ .unicode = i },
// that this works across all keyboard layouts. This may
// want to be true on other platforms as well but this
// is definitely true on macOS so we just do it here for
// now (#817)
.key = if (comptime builtin.target.os.tag.isDarwin())
.{ .physical = @enumFromInt(i) }
else
.{ .translated = @enumFromInt(i) },
.mods = mods, .mods = mods,
}, },
.{ .goto_tab = (i - start) + 1 }, .{ .goto_tab = (i - start) + 1 },
@ -4700,10 +4691,7 @@ pub const Keybinds = struct {
try self.set.put( try self.set.put(
alloc, alloc,
.{ .{
.key = if (comptime builtin.target.os.tag.isDarwin()) .key = .{ .unicode = '9' },
.{ .physical = .nine }
else
.{ .translated = .nine },
.mods = mods, .mods = mods,
}, },
.{ .last_tab = {} }, .{ .last_tab = {} },
@ -4713,14 +4701,14 @@ pub const Keybinds = struct {
// Toggle fullscreen // Toggle fullscreen
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .enter }, .mods = inputpkg.ctrlOrSuper(.{}) }, .{ .key = .{ .physical = .enter }, .mods = inputpkg.ctrlOrSuper(.{}) },
.{ .toggle_fullscreen = {} }, .{ .toggle_fullscreen = {} },
); );
// Toggle zoom a split // Toggle zoom a split
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .enter }, .mods = inputpkg.ctrlOrSuper(.{ .shift = true }) }, .{ .key = .{ .physical = .enter }, .mods = inputpkg.ctrlOrSuper(.{ .shift = true }) },
.{ .toggle_split_zoom = {} }, .{ .toggle_split_zoom = {} },
); );
@ -4728,199 +4716,199 @@ pub const Keybinds = struct {
if (comptime builtin.target.os.tag.isDarwin()) { if (comptime builtin.target.os.tag.isDarwin()) {
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .q }, .mods = .{ .super = true } }, .{ .key = .{ .unicode = 'q' }, .mods = .{ .super = true } },
.{ .quit = {} }, .{ .quit = {} },
); );
try self.set.putFlags( try self.set.putFlags(
alloc, alloc,
.{ .key = .{ .translated = .k }, .mods = .{ .super = true } }, .{ .key = .{ .unicode = 'k' }, .mods = .{ .super = true } },
.{ .clear_screen = {} }, .{ .clear_screen = {} },
.{ .performable = true }, .{ .performable = true },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .a }, .mods = .{ .super = true } }, .{ .key = .{ .unicode = 'a' }, .mods = .{ .super = true } },
.{ .select_all = {} }, .{ .select_all = {} },
); );
// Viewport scrolling // Viewport scrolling
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .home }, .mods = .{ .super = true } }, .{ .key = .{ .physical = .home }, .mods = .{ .super = true } },
.{ .scroll_to_top = {} }, .{ .scroll_to_top = {} },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .end }, .mods = .{ .super = true } }, .{ .key = .{ .physical = .end }, .mods = .{ .super = true } },
.{ .scroll_to_bottom = {} }, .{ .scroll_to_bottom = {} },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .page_up }, .mods = .{ .super = true } }, .{ .key = .{ .physical = .page_up }, .mods = .{ .super = true } },
.{ .scroll_page_up = {} }, .{ .scroll_page_up = {} },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .page_down }, .mods = .{ .super = true } }, .{ .key = .{ .physical = .page_down }, .mods = .{ .super = true } },
.{ .scroll_page_down = {} }, .{ .scroll_page_down = {} },
); );
// Semantic prompts // Semantic prompts
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .up }, .mods = .{ .super = true, .shift = true } }, .{ .key = .{ .physical = .arrow_up }, .mods = .{ .super = true, .shift = true } },
.{ .jump_to_prompt = -1 }, .{ .jump_to_prompt = -1 },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .down }, .mods = .{ .super = true, .shift = true } }, .{ .key = .{ .physical = .arrow_down }, .mods = .{ .super = true, .shift = true } },
.{ .jump_to_prompt = 1 }, .{ .jump_to_prompt = 1 },
); );
// Mac windowing // Mac windowing
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .n }, .mods = .{ .super = true } }, .{ .key = .{ .unicode = 'n' }, .mods = .{ .super = true } },
.{ .new_window = {} }, .{ .new_window = {} },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .w }, .mods = .{ .super = true } }, .{ .key = .{ .unicode = 'w' }, .mods = .{ .super = true } },
.{ .close_surface = {} }, .{ .close_surface = {} },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .w }, .mods = .{ .super = true, .alt = true } }, .{ .key = .{ .unicode = 'w' }, .mods = .{ .super = true, .alt = true } },
.{ .close_tab = {} }, .{ .close_tab = {} },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .w }, .mods = .{ .super = true, .shift = true } }, .{ .key = .{ .unicode = 'w' }, .mods = .{ .super = true, .shift = true } },
.{ .close_window = {} }, .{ .close_window = {} },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .w }, .mods = .{ .super = true, .shift = true, .alt = true } }, .{ .key = .{ .unicode = 'w' }, .mods = .{ .super = true, .shift = true, .alt = true } },
.{ .close_all_windows = {} }, .{ .close_all_windows = {} },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .t }, .mods = .{ .super = true } }, .{ .key = .{ .unicode = 't' }, .mods = .{ .super = true } },
.{ .new_tab = {} }, .{ .new_tab = {} },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .left_bracket }, .mods = .{ .super = true, .shift = true } }, .{ .key = .{ .physical = .bracket_left }, .mods = .{ .super = true, .shift = true } },
.{ .previous_tab = {} }, .{ .previous_tab = {} },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .right_bracket }, .mods = .{ .super = true, .shift = true } }, .{ .key = .{ .physical = .bracket_right }, .mods = .{ .super = true, .shift = true } },
.{ .next_tab = {} }, .{ .next_tab = {} },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .d }, .mods = .{ .super = true } }, .{ .key = .{ .unicode = 'd' }, .mods = .{ .super = true } },
.{ .new_split = .right }, .{ .new_split = .right },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .d }, .mods = .{ .super = true, .shift = true } }, .{ .key = .{ .unicode = 'd' }, .mods = .{ .super = true, .shift = true } },
.{ .new_split = .down }, .{ .new_split = .down },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .left_bracket }, .mods = .{ .super = true } }, .{ .key = .{ .physical = .bracket_left }, .mods = .{ .super = true } },
.{ .goto_split = .previous }, .{ .goto_split = .previous },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .right_bracket }, .mods = .{ .super = true } }, .{ .key = .{ .physical = .bracket_right }, .mods = .{ .super = true } },
.{ .goto_split = .next }, .{ .goto_split = .next },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .up }, .mods = .{ .super = true, .alt = true } }, .{ .key = .{ .physical = .arrow_up }, .mods = .{ .super = true, .alt = true } },
.{ .goto_split = .up }, .{ .goto_split = .up },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .down }, .mods = .{ .super = true, .alt = true } }, .{ .key = .{ .physical = .arrow_down }, .mods = .{ .super = true, .alt = true } },
.{ .goto_split = .down }, .{ .goto_split = .down },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .left }, .mods = .{ .super = true, .alt = true } }, .{ .key = .{ .physical = .arrow_left }, .mods = .{ .super = true, .alt = true } },
.{ .goto_split = .left }, .{ .goto_split = .left },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .right }, .mods = .{ .super = true, .alt = true } }, .{ .key = .{ .physical = .arrow_right }, .mods = .{ .super = true, .alt = true } },
.{ .goto_split = .right }, .{ .goto_split = .right },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .up }, .mods = .{ .super = true, .ctrl = true } }, .{ .key = .{ .physical = .arrow_up }, .mods = .{ .super = true, .ctrl = true } },
.{ .resize_split = .{ .up, 10 } }, .{ .resize_split = .{ .up, 10 } },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .down }, .mods = .{ .super = true, .ctrl = true } }, .{ .key = .{ .physical = .arrow_down }, .mods = .{ .super = true, .ctrl = true } },
.{ .resize_split = .{ .down, 10 } }, .{ .resize_split = .{ .down, 10 } },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .left }, .mods = .{ .super = true, .ctrl = true } }, .{ .key = .{ .physical = .arrow_left }, .mods = .{ .super = true, .ctrl = true } },
.{ .resize_split = .{ .left, 10 } }, .{ .resize_split = .{ .left, 10 } },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .right }, .mods = .{ .super = true, .ctrl = true } }, .{ .key = .{ .physical = .arrow_right }, .mods = .{ .super = true, .ctrl = true } },
.{ .resize_split = .{ .right, 10 } }, .{ .resize_split = .{ .right, 10 } },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .equal }, .mods = .{ .super = true, .ctrl = true } }, .{ .key = .{ .physical = .equal }, .mods = .{ .super = true, .ctrl = true } },
.{ .equalize_splits = {} }, .{ .equalize_splits = {} },
); );
// Jump to prompt, matches Terminal.app // Jump to prompt, matches Terminal.app
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .up }, .mods = .{ .super = true } }, .{ .key = .{ .physical = .arrow_up }, .mods = .{ .super = true } },
.{ .jump_to_prompt = -1 }, .{ .jump_to_prompt = -1 },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .down }, .mods = .{ .super = true } }, .{ .key = .{ .physical = .arrow_down }, .mods = .{ .super = true } },
.{ .jump_to_prompt = 1 }, .{ .jump_to_prompt = 1 },
); );
// Toggle command palette, matches VSCode // Toggle command palette, matches VSCode
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .p }, .mods = .{ .super = true, .shift = true } }, .{ .key = .{ .unicode = 'p' }, .mods = .{ .super = true, .shift = true } },
.{ .toggle_command_palette = {} }, .{ .toggle_command_palette = {} },
); );
// Inspector, matching Chromium // Inspector, matching Chromium
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .i }, .mods = .{ .alt = true, .super = true } }, .{ .key = .{ .unicode = 'i' }, .mods = .{ .alt = true, .super = true } },
.{ .inspector = .toggle }, .{ .inspector = .toggle },
); );
// Alternate keybind, common to Mac programs // Alternate keybind, common to Mac programs
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .f }, .mods = .{ .super = true, .ctrl = true } }, .{ .key = .{ .unicode = 'f' }, .mods = .{ .super = true, .ctrl = true } },
.{ .toggle_fullscreen = {} }, .{ .toggle_fullscreen = {} },
); );
// Selection clipboard paste, matches Terminal.app // Selection clipboard paste, matches Terminal.app
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .v }, .mods = .{ .super = true, .shift = true } }, .{ .key = .{ .unicode = 'v' }, .mods = .{ .super = true, .shift = true } },
.{ .paste_from_selection = {} }, .{ .paste_from_selection = {} },
); );
@ -4931,27 +4919,27 @@ pub const Keybinds = struct {
// the keybinds to `unbind`. // the keybinds to `unbind`.
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .right }, .mods = .{ .super = true } }, .{ .key = .{ .physical = .arrow_right }, .mods = .{ .super = true } },
.{ .text = "\\x05" }, .{ .text = "\\x05" },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .left }, .mods = .{ .super = true } }, .{ .key = .{ .physical = .arrow_left }, .mods = .{ .super = true } },
.{ .text = "\\x01" }, .{ .text = "\\x01" },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .backspace }, .mods = .{ .super = true } }, .{ .key = .{ .physical = .backspace }, .mods = .{ .super = true } },
.{ .text = "\\x15" }, .{ .text = "\\x15" },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .left }, .mods = .{ .alt = true } }, .{ .key = .{ .physical = .arrow_left }, .mods = .{ .alt = true } },
.{ .esc = "b" }, .{ .esc = "b" },
); );
try self.set.put( try self.set.put(
alloc, alloc,
.{ .key = .{ .translated = .right }, .mods = .{ .alt = true } }, .{ .key = .{ .physical = .arrow_right }, .mods = .{ .alt = true } },
.{ .esc = "f" }, .{ .esc = "f" },
); );
} }
@ -5138,8 +5126,8 @@ pub const Keybinds = struct {
// Note they turn into translated keys because they match // Note they turn into translated keys because they match
// their ASCII mapping. // their ASCII mapping.
const want = const want =
\\keybind = ctrl+z>two=goto_tab:2 \\keybind = ctrl+z>2=goto_tab:2
\\keybind = ctrl+z>one=goto_tab:1 \\keybind = ctrl+z>1=goto_tab:1
\\ \\
; ;
try std.testing.expectEqualStrings(want, buf.items); try std.testing.expectEqualStrings(want, buf.items);
@ -5163,8 +5151,8 @@ pub const Keybinds = struct {
// NB: This does not currently retain the order of the keybinds. // NB: This does not currently retain the order of the keybinds.
const want = const want =
\\a = ctrl+a>ctrl+b>w=close_window
\\a = ctrl+a>ctrl+b>n=new_window \\a = ctrl+a>ctrl+b>n=new_window
\\a = ctrl+a>ctrl+b>w=close_window
\\a = ctrl+a>ctrl+c>t=new_tab \\a = ctrl+a>ctrl+c>t=new_tab
\\a = ctrl+b>ctrl+d>a=previous_tab \\a = ctrl+b>ctrl+d>a=previous_tab
\\ \\

View File

@ -99,9 +99,12 @@ pub const Parser = struct {
if (flags.performable) return Error.InvalidFormat; if (flags.performable) return Error.InvalidFormat;
flags.performable = true; flags.performable = true;
} else { } else {
// If we don't recognize the prefix then we're done. // If we don't recognize the prefix then we're done. We
// There are trigger-specific prefixes like "physical:" so // let any unknown prefix fallthrough to trigger-specific
// this lets us fall into that. // parsing in case there are trigger-specific prefixes
// (none currently but historically there was `physical:`
// at one point). Breaking here lets us always implement new
// prefixes.
break; break;
} }
@ -202,14 +205,12 @@ pub fn lessThan(_: void, lhs: Binding, rhs: Binding) bool {
const lhs_key: c_int = blk: { const lhs_key: c_int = blk: {
switch (lhs.trigger.key) { switch (lhs.trigger.key) {
.translated => break :blk @intFromEnum(lhs.trigger.key.translated),
.physical => break :blk @intFromEnum(lhs.trigger.key.physical), .physical => break :blk @intFromEnum(lhs.trigger.key.physical),
.unicode => break :blk @intCast(lhs.trigger.key.unicode), .unicode => break :blk @intCast(lhs.trigger.key.unicode),
} }
}; };
const rhs_key: c_int = blk: { const rhs_key: c_int = blk: {
switch (rhs.trigger.key) { switch (rhs.trigger.key) {
.translated => break :blk @intFromEnum(rhs.trigger.key.translated),
.physical => break :blk @intFromEnum(rhs.trigger.key.physical), .physical => break :blk @intFromEnum(rhs.trigger.key.physical),
.unicode => break :blk @intCast(rhs.trigger.key.unicode), .unicode => break :blk @intCast(rhs.trigger.key.unicode),
} }
@ -1065,18 +1066,12 @@ pub const Action = union(enum) {
/// This must be kept in sync with include/ghostty.h ghostty_input_trigger_s /// This must be kept in sync with include/ghostty.h ghostty_input_trigger_s
pub const Trigger = struct { pub const Trigger = struct {
/// The key that has to be pressed for a binding to take action. /// The key that has to be pressed for a binding to take action.
key: Trigger.Key = .{ .translated = .invalid }, key: Trigger.Key = .{ .physical = .unidentified },
/// The key modifiers that must be active for this to match. /// The key modifiers that must be active for this to match.
mods: key.Mods = .{}, mods: key.Mods = .{},
pub const Key = union(C.Tag) { pub const Key = union(C.Tag) {
/// key is the translated version of a key. This is the key that
/// a logical keyboard layout at the OS level would translate the
/// physical key to. For example if you use a US hardware keyboard
/// but have a Dvorak layout, the key would be the Dvorak key.
translated: key.Key,
/// key is the "physical" version. This is the same as mapped for /// key is the "physical" version. This is the same as mapped for
/// standard US keyboard layouts. For non-US keyboard layouts, this /// standard US keyboard layouts. For non-US keyboard layouts, this
/// is used to bind to a physical key location rather than a translated /// is used to bind to a physical key location rather than a translated
@ -1091,18 +1086,16 @@ pub const Trigger = struct {
/// The extern struct used for triggers in the C API. /// The extern struct used for triggers in the C API.
pub const C = extern struct { pub const C = extern struct {
tag: Tag = .translated, tag: Tag = .physical,
key: C.Key = .{ .translated = .invalid }, key: C.Key = .{ .physical = .unidentified },
mods: key.Mods = .{}, mods: key.Mods = .{},
pub const Tag = enum(c_int) { pub const Tag = enum(c_int) {
translated,
physical, physical,
unicode, unicode,
}; };
pub const Key = extern union { pub const Key = extern union {
translated: key.Key,
physical: key.Key, physical: key.Key,
unicode: u32, unicode: u32,
}; };
@ -1150,24 +1143,16 @@ pub const Trigger = struct {
} }
} }
// If the key starts with "physical" then this is an physical key.
const physical_prefix = "physical:";
const physical = std.mem.startsWith(u8, part, physical_prefix);
const key_part = if (physical) part[physical_prefix.len..] else part;
// Check if its a key // Check if its a key
const keysInfo = @typeInfo(key.Key).@"enum"; const keysInfo = @typeInfo(key.Key).@"enum";
inline for (keysInfo.fields) |field| { inline for (keysInfo.fields) |field| {
if (!std.mem.eql(u8, field.name, "invalid")) { if (!std.mem.eql(u8, field.name, "unidentified")) {
if (std.mem.eql(u8, key_part, field.name)) { if (std.mem.eql(u8, part, field.name)) {
// Repeat not allowed // Repeat not allowed
if (!result.isKeyUnset()) return Error.InvalidFormat; if (!result.isKeyUnset()) return Error.InvalidFormat;
const keyval = @field(key.Key, field.name); const keyval = @field(key.Key, field.name);
result.key = if (physical) result.key = .{ .physical = keyval };
.{ .physical = keyval }
else
.{ .translated = keyval };
continue :loop; continue :loop;
} }
} }
@ -1177,21 +1162,13 @@ pub const Trigger = struct {
// character then we can use that as a key. // character then we can use that as a key.
if (result.isKeyUnset()) unicode: { if (result.isKeyUnset()) unicode: {
// Invalid UTF8 drops to invalid format // Invalid UTF8 drops to invalid format
const view = std.unicode.Utf8View.init(key_part) catch break :unicode; const view = std.unicode.Utf8View.init(part) catch break :unicode;
var it = view.iterator(); var it = view.iterator();
// No codepoints or multiple codepoints drops to invalid format // No codepoints or multiple codepoints drops to invalid format
const cp = it.nextCodepoint() orelse break :unicode; const cp = it.nextCodepoint() orelse break :unicode;
if (it.nextCodepoint() != null) break :unicode; if (it.nextCodepoint() != null) break :unicode;
// If this is ASCII and we have a translated key, set that.
if (std.math.cast(u8, cp)) |ascii| {
if (key.Key.fromASCII(ascii)) |k| {
result.key = .{ .translated = k };
continue :loop;
}
}
result.key = .{ .unicode = cp }; result.key = .{ .unicode = cp };
continue :loop; continue :loop;
} }
@ -1205,7 +1182,7 @@ pub const Trigger = struct {
/// Returns true if this trigger has no key set. /// Returns true if this trigger has no key set.
pub fn isKeyUnset(self: Trigger) bool { pub fn isKeyUnset(self: Trigger) bool {
return switch (self.key) { return switch (self.key) {
.translated => |v| v == .invalid, .physical => |v| v == .unidentified,
else => false, else => false,
}; };
} }
@ -1228,7 +1205,6 @@ pub const Trigger = struct {
return .{ return .{
.tag = self.key, .tag = self.key,
.key = switch (self.key) { .key = switch (self.key) {
.translated => |v| .{ .translated = v },
.physical => |v| .{ .physical = v }, .physical => |v| .{ .physical = v },
.unicode => |v| .{ .unicode = @intCast(v) }, .unicode => |v| .{ .unicode = @intCast(v) },
}, },
@ -1254,8 +1230,7 @@ pub const Trigger = struct {
// Key // Key
switch (self.key) { switch (self.key) {
.translated => |k| try writer.print("{s}", .{@tagName(k)}), .physical => |k| try writer.print("{s}", .{@tagName(k)}),
.physical => |k| try writer.print("physical:{s}", .{@tagName(k)}),
.unicode => |c| try writer.print("{u}", .{c}), .unicode => |c| try writer.print("{u}", .{c}),
} }
} }
@ -1620,13 +1595,10 @@ pub const Set = struct {
pub fn getEvent(self: *const Set, event: KeyEvent) ?Entry { pub fn getEvent(self: *const Set, event: KeyEvent) ?Entry {
var trigger: Trigger = .{ var trigger: Trigger = .{
.mods = event.mods.binding(), .mods = event.mods.binding(),
.key = .{ .translated = event.key }, .key = .{ .physical = event.physical_key },
}; };
if (self.get(trigger)) |v| return v; if (self.get(trigger)) |v| return v;
trigger.key = .{ .physical = event.physical_key };
if (self.get(trigger)) |v| return v;
if (event.unshifted_codepoint > 0) { if (event.unshifted_codepoint > 0) {
trigger.key = .{ .unicode = event.unshifted_codepoint }; trigger.key = .{ .unicode = event.unshifted_codepoint };
if (self.get(trigger)) |v| return v; if (self.get(trigger)) |v| return v;
@ -1637,19 +1609,7 @@ pub const Set = struct {
/// Remove a binding for a given trigger. /// Remove a binding for a given trigger.
pub fn remove(self: *Set, alloc: Allocator, t: Trigger) void { pub fn remove(self: *Set, alloc: Allocator, t: Trigger) void {
// Remove whatever this trigger is
self.removeExact(alloc, t); self.removeExact(alloc, t);
// If we have a physical we remove translated and vice versa.
const alternate: Trigger.Key = switch (t.key) {
.unicode => return,
.translated => |k| .{ .physical = k },
.physical => |k| .{ .translated = k },
};
var alt_t: Trigger = t;
alt_t.key = alternate;
self.removeExact(alloc, alt_t);
} }
fn removeExact(self: *Set, alloc: Allocator, t: Trigger) void { fn removeExact(self: *Set, alloc: Allocator, t: Trigger) void {
@ -1750,37 +1710,24 @@ test "parse: triggers" {
// single character // single character
try testing.expectEqual( try testing.expectEqual(
Binding{ Binding{
.trigger = .{ .key = .{ .translated = .a } }, .trigger = .{ .key = .{ .unicode = 'a' } },
.action = .{ .ignore = {} }, .action = .{ .ignore = {} },
}, },
try parseSingle("a=ignore"), try parseSingle("a=ignore"),
); );
// unicode keys that map to translated
try testing.expectEqual(Binding{
.trigger = .{ .key = .{ .translated = .one } },
.action = .{ .ignore = {} },
}, try parseSingle("1=ignore"));
try testing.expectEqual(Binding{
.trigger = .{
.mods = .{ .super = true },
.key = .{ .translated = .period },
},
.action = .{ .ignore = {} },
}, try parseSingle("cmd+.=ignore"));
// single modifier // single modifier
try testing.expectEqual(Binding{ try testing.expectEqual(Binding{
.trigger = .{ .trigger = .{
.mods = .{ .shift = true }, .mods = .{ .shift = true },
.key = .{ .translated = .a }, .key = .{ .unicode = 'a' },
}, },
.action = .{ .ignore = {} }, .action = .{ .ignore = {} },
}, try parseSingle("shift+a=ignore")); }, try parseSingle("shift+a=ignore"));
try testing.expectEqual(Binding{ try testing.expectEqual(Binding{
.trigger = .{ .trigger = .{
.mods = .{ .ctrl = true }, .mods = .{ .ctrl = true },
.key = .{ .translated = .a }, .key = .{ .unicode = 'a' },
}, },
.action = .{ .ignore = {} }, .action = .{ .ignore = {} },
}, try parseSingle("ctrl+a=ignore")); }, try parseSingle("ctrl+a=ignore"));
@ -1789,7 +1736,7 @@ test "parse: triggers" {
try testing.expectEqual(Binding{ try testing.expectEqual(Binding{
.trigger = .{ .trigger = .{
.mods = .{ .shift = true, .ctrl = true }, .mods = .{ .shift = true, .ctrl = true },
.key = .{ .translated = .a }, .key = .{ .unicode = 'a' },
}, },
.action = .{ .ignore = {} }, .action = .{ .ignore = {} },
}, try parseSingle("shift+ctrl+a=ignore")); }, try parseSingle("shift+ctrl+a=ignore"));
@ -1798,7 +1745,7 @@ test "parse: triggers" {
try testing.expectEqual(Binding{ try testing.expectEqual(Binding{
.trigger = .{ .trigger = .{
.mods = .{ .shift = true }, .mods = .{ .shift = true },
.key = .{ .translated = .a }, .key = .{ .unicode = 'a' },
}, },
.action = .{ .ignore = {} }, .action = .{ .ignore = {} },
}, try parseSingle("a+shift=ignore")); }, try parseSingle("a+shift=ignore"));
@ -1807,10 +1754,10 @@ test "parse: triggers" {
try testing.expectEqual(Binding{ try testing.expectEqual(Binding{
.trigger = .{ .trigger = .{
.mods = .{ .shift = true }, .mods = .{ .shift = true },
.key = .{ .physical = .a }, .key = .{ .physical = .key_a },
}, },
.action = .{ .ignore = {} }, .action = .{ .ignore = {} },
}, try parseSingle("shift+physical:a=ignore")); }, try parseSingle("shift+key_a=ignore"));
// unicode keys // unicode keys
try testing.expectEqual(Binding{ try testing.expectEqual(Binding{
@ -1825,7 +1772,7 @@ test "parse: triggers" {
try testing.expectEqual(Binding{ try testing.expectEqual(Binding{
.trigger = .{ .trigger = .{
.mods = .{ .shift = true }, .mods = .{ .shift = true },
.key = .{ .translated = .a }, .key = .{ .unicode = 'a' },
}, },
.action = .{ .ignore = {} }, .action = .{ .ignore = {} },
.flags = .{ .consumed = false }, .flags = .{ .consumed = false },
@ -1835,17 +1782,17 @@ test "parse: triggers" {
try testing.expectEqual(Binding{ try testing.expectEqual(Binding{
.trigger = .{ .trigger = .{
.mods = .{ .shift = true }, .mods = .{ .shift = true },
.key = .{ .physical = .a }, .key = .{ .physical = .key_a },
}, },
.action = .{ .ignore = {} }, .action = .{ .ignore = {} },
.flags = .{ .consumed = false }, .flags = .{ .consumed = false },
}, try parseSingle("unconsumed:physical:a+shift=ignore")); }, try parseSingle("unconsumed:key_a+shift=ignore"));
// performable keys // performable keys
try testing.expectEqual(Binding{ try testing.expectEqual(Binding{
.trigger = .{ .trigger = .{
.mods = .{ .shift = true }, .mods = .{ .shift = true },
.key = .{ .translated = .a }, .key = .{ .unicode = 'a' },
}, },
.action = .{ .ignore = {} }, .action = .{ .ignore = {} },
.flags = .{ .performable = true }, .flags = .{ .performable = true },
@ -1868,7 +1815,7 @@ test "parse: global triggers" {
try testing.expectEqual(Binding{ try testing.expectEqual(Binding{
.trigger = .{ .trigger = .{
.mods = .{ .shift = true }, .mods = .{ .shift = true },
.key = .{ .translated = .a }, .key = .{ .unicode = 'a' },
}, },
.action = .{ .ignore = {} }, .action = .{ .ignore = {} },
.flags = .{ .global = true }, .flags = .{ .global = true },
@ -1878,17 +1825,17 @@ test "parse: global triggers" {
try testing.expectEqual(Binding{ try testing.expectEqual(Binding{
.trigger = .{ .trigger = .{
.mods = .{ .shift = true }, .mods = .{ .shift = true },
.key = .{ .physical = .a }, .key = .{ .physical = .key_a },
}, },
.action = .{ .ignore = {} }, .action = .{ .ignore = {} },
.flags = .{ .global = true }, .flags = .{ .global = true },
}, try parseSingle("global:physical:a+shift=ignore")); }, try parseSingle("global:key_a+shift=ignore"));
// global unconsumed keys // global unconsumed keys
try testing.expectEqual(Binding{ try testing.expectEqual(Binding{
.trigger = .{ .trigger = .{
.mods = .{ .shift = true }, .mods = .{ .shift = true },
.key = .{ .translated = .a }, .key = .{ .unicode = 'a' },
}, },
.action = .{ .ignore = {} }, .action = .{ .ignore = {} },
.flags = .{ .flags = .{
@ -1911,7 +1858,7 @@ test "parse: all triggers" {
try testing.expectEqual(Binding{ try testing.expectEqual(Binding{
.trigger = .{ .trigger = .{
.mods = .{ .shift = true }, .mods = .{ .shift = true },
.key = .{ .translated = .a }, .key = .{ .unicode = 'a' },
}, },
.action = .{ .ignore = {} }, .action = .{ .ignore = {} },
.flags = .{ .all = true }, .flags = .{ .all = true },
@ -1921,17 +1868,17 @@ test "parse: all triggers" {
try testing.expectEqual(Binding{ try testing.expectEqual(Binding{
.trigger = .{ .trigger = .{
.mods = .{ .shift = true }, .mods = .{ .shift = true },
.key = .{ .physical = .a }, .key = .{ .physical = .key_a },
}, },
.action = .{ .ignore = {} }, .action = .{ .ignore = {} },
.flags = .{ .all = true }, .flags = .{ .all = true },
}, try parseSingle("all:physical:a+shift=ignore")); }, try parseSingle("all:key_a+shift=ignore"));
// all unconsumed keys // all unconsumed keys
try testing.expectEqual(Binding{ try testing.expectEqual(Binding{
.trigger = .{ .trigger = .{
.mods = .{ .shift = true }, .mods = .{ .shift = true },
.key = .{ .translated = .a }, .key = .{ .unicode = 'a' },
}, },
.action = .{ .ignore = {} }, .action = .{ .ignore = {} },
.flags = .{ .flags = .{
@ -1953,14 +1900,14 @@ test "parse: modifier aliases" {
try testing.expectEqual(Binding{ try testing.expectEqual(Binding{
.trigger = .{ .trigger = .{
.mods = .{ .super = true }, .mods = .{ .super = true },
.key = .{ .translated = .a }, .key = .{ .unicode = 'a' },
}, },
.action = .{ .ignore = {} }, .action = .{ .ignore = {} },
}, try parseSingle("cmd+a=ignore")); }, try parseSingle("cmd+a=ignore"));
try testing.expectEqual(Binding{ try testing.expectEqual(Binding{
.trigger = .{ .trigger = .{
.mods = .{ .super = true }, .mods = .{ .super = true },
.key = .{ .translated = .a }, .key = .{ .unicode = 'a' },
}, },
.action = .{ .ignore = {} }, .action = .{ .ignore = {} },
}, try parseSingle("command+a=ignore")); }, try parseSingle("command+a=ignore"));
@ -1968,14 +1915,14 @@ test "parse: modifier aliases" {
try testing.expectEqual(Binding{ try testing.expectEqual(Binding{
.trigger = .{ .trigger = .{
.mods = .{ .alt = true }, .mods = .{ .alt = true },
.key = .{ .translated = .a }, .key = .{ .unicode = 'a' },
}, },
.action = .{ .ignore = {} }, .action = .{ .ignore = {} },
}, try parseSingle("opt+a=ignore")); }, try parseSingle("opt+a=ignore"));
try testing.expectEqual(Binding{ try testing.expectEqual(Binding{
.trigger = .{ .trigger = .{
.mods = .{ .alt = true }, .mods = .{ .alt = true },
.key = .{ .translated = .a }, .key = .{ .unicode = 'a' },
}, },
.action = .{ .ignore = {} }, .action = .{ .ignore = {} },
}, try parseSingle("option+a=ignore")); }, try parseSingle("option+a=ignore"));
@ -1983,7 +1930,7 @@ test "parse: modifier aliases" {
try testing.expectEqual(Binding{ try testing.expectEqual(Binding{
.trigger = .{ .trigger = .{
.mods = .{ .ctrl = true }, .mods = .{ .ctrl = true },
.key = .{ .translated = .a }, .key = .{ .unicode = 'a' },
}, },
.action = .{ .ignore = {} }, .action = .{ .ignore = {} },
}, try parseSingle("control+a=ignore")); }, try parseSingle("control+a=ignore"));
@ -2002,7 +1949,7 @@ test "parse: action no parameters" {
// no parameters // no parameters
try testing.expectEqual( try testing.expectEqual(
Binding{ Binding{
.trigger = .{ .key = .{ .translated = .a } }, .trigger = .{ .key = .{ .unicode = 'a' } },
.action = .{ .ignore = {} }, .action = .{ .ignore = {} },
}, },
try parseSingle("a=ignore"), try parseSingle("a=ignore"),
@ -2108,15 +2055,15 @@ test "sequence iterator" {
// single character // single character
{ {
var it: SequenceIterator = .{ .input = "a" }; var it: SequenceIterator = .{ .input = "a" };
try testing.expectEqual(Trigger{ .key = .{ .translated = .a } }, (try it.next()).?); try testing.expectEqual(Trigger{ .key = .{ .unicode = 'a' } }, (try it.next()).?);
try testing.expect(try it.next() == null); try testing.expect(try it.next() == null);
} }
// multi character // multi character
{ {
var it: SequenceIterator = .{ .input = "a>b" }; var it: SequenceIterator = .{ .input = "a>b" };
try testing.expectEqual(Trigger{ .key = .{ .translated = .a } }, (try it.next()).?); try testing.expectEqual(Trigger{ .key = .{ .unicode = 'a' } }, (try it.next()).?);
try testing.expectEqual(Trigger{ .key = .{ .translated = .b } }, (try it.next()).?); try testing.expectEqual(Trigger{ .key = .{ .unicode = 'b' } }, (try it.next()).?);
try testing.expect(try it.next() == null); try testing.expect(try it.next() == null);
} }
@ -2135,7 +2082,7 @@ test "sequence iterator" {
// empty ending sequence // empty ending sequence
{ {
var it: SequenceIterator = .{ .input = "a>" }; var it: SequenceIterator = .{ .input = "a>" };
try testing.expectEqual(Trigger{ .key = .{ .translated = .a } }, (try it.next()).?); try testing.expectEqual(Trigger{ .key = .{ .unicode = 'a' } }, (try it.next()).?);
try testing.expectError(Error.InvalidFormat, it.next()); try testing.expectError(Error.InvalidFormat, it.next());
} }
} }
@ -2149,7 +2096,7 @@ test "parse: sequences" {
try testing.expectEqual(Parser.Elem{ .binding = .{ try testing.expectEqual(Parser.Elem{ .binding = .{
.trigger = .{ .trigger = .{
.mods = .{ .ctrl = true }, .mods = .{ .ctrl = true },
.key = .{ .translated = .a }, .key = .{ .unicode = 'a' },
}, },
.action = .{ .ignore = {} }, .action = .{ .ignore = {} },
} }, (try p.next()).?); } }, (try p.next()).?);
@ -2160,11 +2107,11 @@ test "parse: sequences" {
{ {
var p = try Parser.init("a>b=ignore"); var p = try Parser.init("a>b=ignore");
try testing.expectEqual(Parser.Elem{ .leader = .{ try testing.expectEqual(Parser.Elem{ .leader = .{
.key = .{ .translated = .a }, .key = .{ .unicode = 'a' },
} }, (try p.next()).?); } }, (try p.next()).?);
try testing.expectEqual(Parser.Elem{ .binding = .{ try testing.expectEqual(Parser.Elem{ .binding = .{
.trigger = .{ .trigger = .{
.key = .{ .translated = .b }, .key = .{ .unicode = 'b' },
}, },
.action = .{ .ignore = {} }, .action = .{ .ignore = {} },
} }, (try p.next()).?); } }, (try p.next()).?);
@ -2183,7 +2130,7 @@ test "set: parseAndPut typical binding" {
// Creates forward mapping // Creates forward mapping
{ {
const action = s.get(.{ .key = .{ .translated = .a } }).?.value_ptr.*.leaf; const action = s.get(.{ .key = .{ .unicode = 'a' } }).?.value_ptr.*.leaf;
try testing.expect(action.action == .new_window); try testing.expect(action.action == .new_window);
try testing.expectEqual(Flags{}, action.flags); try testing.expectEqual(Flags{}, action.flags);
} }
@ -2191,7 +2138,7 @@ test "set: parseAndPut typical binding" {
// Creates reverse mapping // Creates reverse mapping
{ {
const trigger = s.getTrigger(.{ .new_window = {} }).?; const trigger = s.getTrigger(.{ .new_window = {} }).?;
try testing.expect(trigger.key.translated == .a); try testing.expect(trigger.key.unicode == 'a');
} }
} }
@ -2206,7 +2153,7 @@ test "set: parseAndPut unconsumed binding" {
// Creates forward mapping // Creates forward mapping
{ {
const trigger: Trigger = .{ .key = .{ .translated = .a } }; const trigger: Trigger = .{ .key = .{ .unicode = 'a' } };
const action = s.get(trigger).?.value_ptr.*.leaf; const action = s.get(trigger).?.value_ptr.*.leaf;
try testing.expect(action.action == .new_window); try testing.expect(action.action == .new_window);
try testing.expectEqual(Flags{ .consumed = false }, action.flags); try testing.expectEqual(Flags{ .consumed = false }, action.flags);
@ -2215,7 +2162,7 @@ test "set: parseAndPut unconsumed binding" {
// Creates reverse mapping // Creates reverse mapping
{ {
const trigger = s.getTrigger(.{ .new_window = {} }).?; const trigger = s.getTrigger(.{ .new_window = {} }).?;
try testing.expect(trigger.key.translated == .a); try testing.expect(trigger.key.unicode == 'a');
} }
} }
@ -2231,25 +2178,7 @@ test "set: parseAndPut removed binding" {
// Creates forward mapping // Creates forward mapping
{ {
const trigger: Trigger = .{ .key = .{ .translated = .a } }; const trigger: Trigger = .{ .key = .{ .unicode = 'a' } };
try testing.expect(s.get(trigger) == null);
}
try testing.expect(s.getTrigger(.{ .new_window = {} }) == null);
}
test "set: parseAndPut removed physical binding" {
const testing = std.testing;
const alloc = testing.allocator;
var s: Set = .{};
defer s.deinit(alloc);
try s.parseAndPut(alloc, "physical:a=new_window");
try s.parseAndPut(alloc, "a=unbind");
// Creates forward mapping
{
const trigger: Trigger = .{ .key = .{ .physical = .a } };
try testing.expect(s.get(trigger) == null); try testing.expect(s.get(trigger) == null);
} }
try testing.expect(s.getTrigger(.{ .new_window = {} }) == null); try testing.expect(s.getTrigger(.{ .new_window = {} }) == null);
@ -2265,13 +2194,13 @@ test "set: parseAndPut sequence" {
try s.parseAndPut(alloc, "a>b=new_window"); try s.parseAndPut(alloc, "a>b=new_window");
var current: *Set = &s; var current: *Set = &s;
{ {
const t: Trigger = .{ .key = .{ .translated = .a } }; const t: Trigger = .{ .key = .{ .unicode = 'a' } };
const e = current.get(t).?.value_ptr.*; const e = current.get(t).?.value_ptr.*;
try testing.expect(e == .leader); try testing.expect(e == .leader);
current = e.leader; current = e.leader;
} }
{ {
const t: Trigger = .{ .key = .{ .translated = .b } }; const t: Trigger = .{ .key = .{ .unicode = 'b' } };
const e = current.get(t).?.value_ptr.*; const e = current.get(t).?.value_ptr.*;
try testing.expect(e == .leaf); try testing.expect(e == .leaf);
try testing.expect(e.leaf.action == .new_window); try testing.expect(e.leaf.action == .new_window);
@ -2290,20 +2219,20 @@ test "set: parseAndPut sequence with two actions" {
try s.parseAndPut(alloc, "a>c=new_tab"); try s.parseAndPut(alloc, "a>c=new_tab");
var current: *Set = &s; var current: *Set = &s;
{ {
const t: Trigger = .{ .key = .{ .translated = .a } }; const t: Trigger = .{ .key = .{ .unicode = 'a' } };
const e = current.get(t).?.value_ptr.*; const e = current.get(t).?.value_ptr.*;
try testing.expect(e == .leader); try testing.expect(e == .leader);
current = e.leader; current = e.leader;
} }
{ {
const t: Trigger = .{ .key = .{ .translated = .b } }; const t: Trigger = .{ .key = .{ .unicode = 'b' } };
const e = current.get(t).?.value_ptr.*; const e = current.get(t).?.value_ptr.*;
try testing.expect(e == .leaf); try testing.expect(e == .leaf);
try testing.expect(e.leaf.action == .new_window); try testing.expect(e.leaf.action == .new_window);
try testing.expectEqual(Flags{}, e.leaf.flags); try testing.expectEqual(Flags{}, e.leaf.flags);
} }
{ {
const t: Trigger = .{ .key = .{ .translated = .c } }; const t: Trigger = .{ .key = .{ .unicode = 'c' } };
const e = current.get(t).?.value_ptr.*; const e = current.get(t).?.value_ptr.*;
try testing.expect(e == .leaf); try testing.expect(e == .leaf);
try testing.expect(e.leaf.action == .new_tab); try testing.expect(e.leaf.action == .new_tab);
@ -2322,13 +2251,13 @@ test "set: parseAndPut overwrite sequence" {
try s.parseAndPut(alloc, "a>b=new_window"); try s.parseAndPut(alloc, "a>b=new_window");
var current: *Set = &s; var current: *Set = &s;
{ {
const t: Trigger = .{ .key = .{ .translated = .a } }; const t: Trigger = .{ .key = .{ .unicode = 'a' } };
const e = current.get(t).?.value_ptr.*; const e = current.get(t).?.value_ptr.*;
try testing.expect(e == .leader); try testing.expect(e == .leader);
current = e.leader; current = e.leader;
} }
{ {
const t: Trigger = .{ .key = .{ .translated = .b } }; const t: Trigger = .{ .key = .{ .unicode = 'b' } };
const e = current.get(t).?.value_ptr.*; const e = current.get(t).?.value_ptr.*;
try testing.expect(e == .leaf); try testing.expect(e == .leaf);
try testing.expect(e.leaf.action == .new_window); try testing.expect(e.leaf.action == .new_window);
@ -2347,13 +2276,13 @@ test "set: parseAndPut overwrite leader" {
try s.parseAndPut(alloc, "a>b=new_window"); try s.parseAndPut(alloc, "a>b=new_window");
var current: *Set = &s; var current: *Set = &s;
{ {
const t: Trigger = .{ .key = .{ .translated = .a } }; const t: Trigger = .{ .key = .{ .unicode = 'a' } };
const e = current.get(t).?.value_ptr.*; const e = current.get(t).?.value_ptr.*;
try testing.expect(e == .leader); try testing.expect(e == .leader);
current = e.leader; current = e.leader;
} }
{ {
const t: Trigger = .{ .key = .{ .translated = .b } }; const t: Trigger = .{ .key = .{ .unicode = 'b' } };
const e = current.get(t).?.value_ptr.*; const e = current.get(t).?.value_ptr.*;
try testing.expect(e == .leaf); try testing.expect(e == .leaf);
try testing.expect(e.leaf.action == .new_window); try testing.expect(e.leaf.action == .new_window);
@ -2372,7 +2301,7 @@ test "set: parseAndPut unbind sequence unbinds leader" {
try s.parseAndPut(alloc, "a>b=unbind"); try s.parseAndPut(alloc, "a>b=unbind");
var current: *Set = &s; var current: *Set = &s;
{ {
const t: Trigger = .{ .key = .{ .translated = .a } }; const t: Trigger = .{ .key = .{ .unicode = 'a' } };
try testing.expect(current.get(t) == null); try testing.expect(current.get(t) == null);
} }
} }
@ -2387,7 +2316,7 @@ test "set: parseAndPut unbind sequence unbinds leader if not set" {
try s.parseAndPut(alloc, "a>b=unbind"); try s.parseAndPut(alloc, "a>b=unbind");
var current: *Set = &s; var current: *Set = &s;
{ {
const t: Trigger = .{ .key = .{ .translated = .a } }; const t: Trigger = .{ .key = .{ .unicode = 'a' } };
try testing.expect(current.get(t) == null); try testing.expect(current.get(t) == null);
} }
} }
@ -2405,7 +2334,7 @@ test "set: parseAndPut sequence preserves reverse mapping" {
// Creates reverse mapping // Creates reverse mapping
{ {
const trigger = s.getTrigger(.{ .new_window = {} }).?; const trigger = s.getTrigger(.{ .new_window = {} }).?;
try testing.expect(trigger.key.translated == .a); try testing.expect(trigger.key.unicode == 'a');
} }
} }
@ -2419,13 +2348,13 @@ test "set: put overwrites sequence" {
try s.parseAndPut(alloc, "ctrl+a>b=new_window"); try s.parseAndPut(alloc, "ctrl+a>b=new_window");
try s.put(alloc, .{ try s.put(alloc, .{
.mods = .{ .ctrl = true }, .mods = .{ .ctrl = true },
.key = .{ .translated = .a }, .key = .{ .unicode = 'a' },
}, .{ .new_window = {} }); }, .{ .new_window = {} });
// Creates reverse mapping // Creates reverse mapping
{ {
const trigger = s.getTrigger(.{ .new_window = {} }).?; const trigger = s.getTrigger(.{ .new_window = {} }).?;
try testing.expect(trigger.key.translated == .a); try testing.expect(trigger.key.unicode == 'a');
} }
} }
@ -2436,24 +2365,24 @@ test "set: maintains reverse mapping" {
var s: Set = .{}; var s: Set = .{};
defer s.deinit(alloc); defer s.deinit(alloc);
try s.put(alloc, .{ .key = .{ .translated = .a } }, .{ .new_window = {} }); try s.put(alloc, .{ .key = .{ .unicode = 'a' } }, .{ .new_window = {} });
{ {
const trigger = s.getTrigger(.{ .new_window = {} }).?; const trigger = s.getTrigger(.{ .new_window = {} }).?;
try testing.expect(trigger.key.translated == .a); try testing.expect(trigger.key.unicode == 'a');
} }
// should be most recent // should be most recent
try s.put(alloc, .{ .key = .{ .translated = .b } }, .{ .new_window = {} }); try s.put(alloc, .{ .key = .{ .unicode = 'b' } }, .{ .new_window = {} });
{ {
const trigger = s.getTrigger(.{ .new_window = {} }).?; const trigger = s.getTrigger(.{ .new_window = {} }).?;
try testing.expect(trigger.key.translated == .b); try testing.expect(trigger.key.unicode == 'b');
} }
// removal should replace // removal should replace
s.remove(alloc, .{ .key = .{ .translated = .b } }); s.remove(alloc, .{ .key = .{ .unicode = 'b' } });
{ {
const trigger = s.getTrigger(.{ .new_window = {} }).?; const trigger = s.getTrigger(.{ .new_window = {} }).?;
try testing.expect(trigger.key.translated == .a); try testing.expect(trigger.key.unicode == 'a');
} }
} }
@ -2464,29 +2393,29 @@ test "set: performable is not part of reverse mappings" {
var s: Set = .{}; var s: Set = .{};
defer s.deinit(alloc); defer s.deinit(alloc);
try s.put(alloc, .{ .key = .{ .translated = .a } }, .{ .new_window = {} }); try s.put(alloc, .{ .key = .{ .unicode = 'a' } }, .{ .new_window = {} });
{ {
const trigger = s.getTrigger(.{ .new_window = {} }).?; const trigger = s.getTrigger(.{ .new_window = {} }).?;
try testing.expect(trigger.key.translated == .a); try testing.expect(trigger.key.unicode == 'a');
} }
// trigger should be non-performable // trigger should be non-performable
try s.putFlags( try s.putFlags(
alloc, alloc,
.{ .key = .{ .translated = .b } }, .{ .key = .{ .unicode = 'b' } },
.{ .new_window = {} }, .{ .new_window = {} },
.{ .performable = true }, .{ .performable = true },
); );
{ {
const trigger = s.getTrigger(.{ .new_window = {} }).?; const trigger = s.getTrigger(.{ .new_window = {} }).?;
try testing.expect(trigger.key.translated == .a); try testing.expect(trigger.key.unicode == 'a');
} }
// removal of performable should do nothing // removal of performable should do nothing
s.remove(alloc, .{ .key = .{ .translated = .b } }); s.remove(alloc, .{ .key = .{ .unicode = 'b' } });
{ {
const trigger = s.getTrigger(.{ .new_window = {} }).?; const trigger = s.getTrigger(.{ .new_window = {} }).?;
try testing.expect(trigger.key.translated == .a); try testing.expect(trigger.key.unicode == 'a');
} }
} }
@ -2497,14 +2426,14 @@ test "set: overriding a mapping updates reverse" {
var s: Set = .{}; var s: Set = .{};
defer s.deinit(alloc); defer s.deinit(alloc);
try s.put(alloc, .{ .key = .{ .translated = .a } }, .{ .new_window = {} }); try s.put(alloc, .{ .key = .{ .unicode = 'a' } }, .{ .new_window = {} });
{ {
const trigger = s.getTrigger(.{ .new_window = {} }).?; const trigger = s.getTrigger(.{ .new_window = {} }).?;
try testing.expect(trigger.key.translated == .a); try testing.expect(trigger.key.unicode == 'a');
} }
// should be most recent // should be most recent
try s.put(alloc, .{ .key = .{ .translated = .a } }, .{ .new_tab = {} }); try s.put(alloc, .{ .key = .{ .unicode = 'a' } }, .{ .new_tab = {} });
{ {
const trigger = s.getTrigger(.{ .new_window = {} }); const trigger = s.getTrigger(.{ .new_window = {} });
try testing.expect(trigger == null); try testing.expect(trigger == null);
@ -2518,22 +2447,22 @@ test "set: consumed state" {
var s: Set = .{}; var s: Set = .{};
defer s.deinit(alloc); defer s.deinit(alloc);
try s.put(alloc, .{ .key = .{ .translated = .a } }, .{ .new_window = {} }); try s.put(alloc, .{ .key = .{ .unicode = 'a' } }, .{ .new_window = {} });
try testing.expect(s.get(.{ .key = .{ .translated = .a } }).?.value_ptr.* == .leaf); try testing.expect(s.get(.{ .key = .{ .unicode = 'a' } }).?.value_ptr.* == .leaf);
try testing.expect(s.get(.{ .key = .{ .translated = .a } }).?.value_ptr.*.leaf.flags.consumed); try testing.expect(s.get(.{ .key = .{ .unicode = 'a' } }).?.value_ptr.*.leaf.flags.consumed);
try s.putFlags( try s.putFlags(
alloc, alloc,
.{ .key = .{ .translated = .a } }, .{ .key = .{ .unicode = 'a' } },
.{ .new_window = {} }, .{ .new_window = {} },
.{ .consumed = false }, .{ .consumed = false },
); );
try testing.expect(s.get(.{ .key = .{ .translated = .a } }).?.value_ptr.* == .leaf); try testing.expect(s.get(.{ .key = .{ .unicode = 'a' } }).?.value_ptr.* == .leaf);
try testing.expect(!s.get(.{ .key = .{ .translated = .a } }).?.value_ptr.*.leaf.flags.consumed); try testing.expect(!s.get(.{ .key = .{ .unicode = 'a' } }).?.value_ptr.*.leaf.flags.consumed);
try s.put(alloc, .{ .key = .{ .translated = .a } }, .{ .new_window = {} }); try s.put(alloc, .{ .key = .{ .unicode = 'a' } }, .{ .new_window = {} });
try testing.expect(s.get(.{ .key = .{ .translated = .a } }).?.value_ptr.* == .leaf); try testing.expect(s.get(.{ .key = .{ .unicode = 'a' } }).?.value_ptr.* == .leaf);
try testing.expect(s.get(.{ .key = .{ .translated = .a } }).?.value_ptr.*.leaf.flags.consumed); try testing.expect(s.get(.{ .key = .{ .unicode = 'a' } }).?.value_ptr.*.leaf.flags.consumed);
} }
test "Action: clone" { test "Action: clone" {

View File

@ -1082,7 +1082,7 @@ test "kitty: plain text" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.key = .a, .key = .key_a,
.mods = .{}, .mods = .{},
.utf8 = "abcd", .utf8 = "abcd",
}, },
@ -1098,7 +1098,7 @@ test "kitty: repeat with just disambiguate" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.key = .a, .key = .key_a,
.action = .repeat, .action = .repeat,
.mods = .{}, .mods = .{},
.utf8 = "a", .utf8 = "a",
@ -1222,7 +1222,7 @@ test "kitty: enter with all flags" {
test "kitty: ctrl with all flags" { test "kitty: ctrl with all flags" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .key = .left_control, .mods = .{ .ctrl = true }, .utf8 = "" }, .event = .{ .key = .control_left, .mods = .{ .ctrl = true }, .utf8 = "" },
.kitty_flags = .{ .kitty_flags = .{
.disambiguate = true, .disambiguate = true,
.report_events = true, .report_events = true,
@ -1240,7 +1240,7 @@ test "kitty: ctrl release with ctrl mod set" {
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.action = .release, .action = .release,
.key = .left_control, .key = .control_left,
.mods = .{ .ctrl = true }, .mods = .{ .ctrl = true },
.utf8 = "", .utf8 = "",
}, },
@ -1272,7 +1272,7 @@ test "kitty: composing with no modifier" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.key = .a, .key = .key_a,
.mods = .{ .shift = true }, .mods = .{ .shift = true },
.composing = true, .composing = true,
}, },
@ -1287,7 +1287,7 @@ test "kitty: composing with modifier" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.key = .left_shift, .key = .shift_left,
.mods = .{ .shift = true }, .mods = .{ .shift = true },
.composing = true, .composing = true,
}, },
@ -1302,7 +1302,7 @@ test "kitty: shift+a on US keyboard" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.key = .a, .key = .key_a,
.mods = .{ .shift = true }, .mods = .{ .shift = true },
.utf8 = "A", .utf8 = "A",
.unshifted_codepoint = 97, // lowercase A .unshifted_codepoint = 97, // lowercase A
@ -1321,7 +1321,7 @@ test "kitty: matching unshifted codepoint" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.key = .a, .key = .key_a,
.mods = .{ .shift = true }, .mods = .{ .shift = true },
.utf8 = "A", .utf8 = "A",
.unshifted_codepoint = 65, .unshifted_codepoint = 65,
@ -1344,7 +1344,7 @@ test "kitty: report alternates with caps" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.key = .j, .key = .key_j,
.mods = .{ .caps_lock = true }, .mods = .{ .caps_lock = true },
.utf8 = "J", .utf8 = "J",
.unshifted_codepoint = 106, .unshifted_codepoint = 106,
@ -1450,7 +1450,7 @@ test "kitty: report alternates with hu layout release" {
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.action = .release, .action = .release,
.key = .left_bracket, .key = .bracket_left,
.mods = .{ .ctrl = true }, .mods = .{ .ctrl = true },
.utf8 = "", .utf8 = "",
.unshifted_codepoint = 337, .unshifted_codepoint = 337,
@ -1473,7 +1473,7 @@ test "kitty: up arrow with utf8" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.key = .up, .key = .arrow_up,
.mods = .{}, .mods = .{},
.utf8 = &.{30}, .utf8 = &.{30},
}, },
@ -1505,7 +1505,7 @@ test "kitty: left shift" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.key = .left_shift, .key = .shift_left,
.mods = .{}, .mods = .{},
.utf8 = "", .utf8 = "",
}, },
@ -1521,7 +1521,7 @@ test "kitty: left shift with report all" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.key = .left_shift, .key = .shift_left,
.mods = .{}, .mods = .{},
.utf8 = "", .utf8 = "",
}, },
@ -1539,7 +1539,7 @@ test "kitty: report associated with alt text on macOS with option" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.key = .w, .key = .key_w,
.mods = .{ .alt = true }, .mods = .{ .alt = true },
.utf8 = "", .utf8 = "",
.unshifted_codepoint = 119, .unshifted_codepoint = 119,
@ -1565,7 +1565,7 @@ test "kitty: report associated with alt text on macOS with alt" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.key = .w, .key = .key_w,
.mods = .{ .alt = true }, .mods = .{ .alt = true },
.utf8 = "", .utf8 = "",
.unshifted_codepoint = 119, .unshifted_codepoint = 119,
@ -1588,7 +1588,7 @@ test "kitty: report associated with alt text on macOS with alt" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.key = .w, .key = .key_w,
.mods = .{}, .mods = .{},
.utf8 = "", .utf8 = "",
.unshifted_codepoint = 119, .unshifted_codepoint = 119,
@ -1611,7 +1611,7 @@ test "kitty: report associated with modifiers" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.key = .j, .key = .key_j,
.mods = .{ .ctrl = true }, .mods = .{ .ctrl = true },
.utf8 = "j", .utf8 = "j",
.unshifted_codepoint = 106, .unshifted_codepoint = 106,
@ -1632,7 +1632,7 @@ test "kitty: report associated" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.key = .j, .key = .key_j,
.mods = .{ .shift = true }, .mods = .{ .shift = true },
.utf8 = "J", .utf8 = "J",
.unshifted_codepoint = 106, .unshifted_codepoint = 106,
@ -1654,7 +1654,7 @@ test "kitty: report associated on release" {
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.action = .release, .action = .release,
.key = .j, .key = .key_j,
.mods = .{ .shift = true }, .mods = .{ .shift = true },
.utf8 = "J", .utf8 = "J",
.unshifted_codepoint = 106, .unshifted_codepoint = 106,
@ -1713,7 +1713,7 @@ test "kitty: enter with utf8 (dead key state)" {
test "kitty: keypad number" { test "kitty: keypad number" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .key = .kp_1, .mods = .{}, .utf8 = "1" }, .event = .{ .key = .numpad_1, .mods = .{}, .utf8 = "1" },
.kitty_flags = .{ .kitty_flags = .{
.disambiguate = true, .disambiguate = true,
.report_events = true, .report_events = true,
@ -1807,7 +1807,7 @@ test "legacy: ctrl+alt+c" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.key = .c, .key = .key_c,
.mods = .{ .ctrl = true, .alt = true }, .mods = .{ .ctrl = true, .alt = true },
.utf8 = "c", .utf8 = "c",
}, },
@ -1821,7 +1821,7 @@ test "legacy: alt+c" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.key = .c, .key = .key_c,
.utf8 = "c", .utf8 = "c",
.mods = .{ .alt = true }, .mods = .{ .alt = true },
}, },
@ -1837,7 +1837,7 @@ test "legacy: alt+e only unshifted" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.key = .e, .key = .key_e,
.unshifted_codepoint = 'e', .unshifted_codepoint = 'e',
.mods = .{ .alt = true }, .mods = .{ .alt = true },
}, },
@ -1855,7 +1855,7 @@ test "legacy: alt+x macos" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.key = .c, .key = .key_c,
.utf8 = "", .utf8 = "",
.unshifted_codepoint = 'c', .unshifted_codepoint = 'c',
.mods = .{ .alt = true }, .mods = .{ .alt = true },
@ -1891,7 +1891,7 @@ test "legacy: alt+ф" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.key = .f, .key = .key_f,
.utf8 = "ф", .utf8 = "ф",
.mods = .{ .alt = true }, .mods = .{ .alt = true },
}, },
@ -1906,7 +1906,7 @@ test "legacy: ctrl+c" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.key = .c, .key = .key_c,
.mods = .{ .ctrl = true }, .mods = .{ .ctrl = true },
.utf8 = "c", .utf8 = "c",
}, },
@ -1947,7 +1947,7 @@ test "legacy: ctrl+shift+char with modify other state 2" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.key = .h, .key = .key_h,
.mods = .{ .ctrl = true, .shift = true }, .mods = .{ .ctrl = true, .shift = true },
.utf8 = "H", .utf8 = "H",
}, },
@ -1962,7 +1962,7 @@ test "legacy: fixterm awkward letters" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
{ {
var enc: KeyEncoder = .{ .event = .{ var enc: KeyEncoder = .{ .event = .{
.key = .i, .key = .key_i,
.mods = .{ .ctrl = true }, .mods = .{ .ctrl = true },
.utf8 = "i", .utf8 = "i",
} }; } };
@ -1971,7 +1971,7 @@ test "legacy: fixterm awkward letters" {
} }
{ {
var enc: KeyEncoder = .{ .event = .{ var enc: KeyEncoder = .{ .event = .{
.key = .m, .key = .key_m,
.mods = .{ .ctrl = true }, .mods = .{ .ctrl = true },
.utf8 = "m", .utf8 = "m",
} }; } };
@ -1980,7 +1980,7 @@ test "legacy: fixterm awkward letters" {
} }
{ {
var enc: KeyEncoder = .{ .event = .{ var enc: KeyEncoder = .{ .event = .{
.key = .left_bracket, .key = .bracket_left,
.mods = .{ .ctrl = true }, .mods = .{ .ctrl = true },
.utf8 = "[", .utf8 = "[",
} }; } };
@ -1989,7 +1989,7 @@ test "legacy: fixterm awkward letters" {
} }
{ {
var enc: KeyEncoder = .{ .event = .{ var enc: KeyEncoder = .{ .event = .{
.key = .two, .key = .digit_2,
.mods = .{ .ctrl = true, .shift = true }, .mods = .{ .ctrl = true, .shift = true },
.utf8 = "@", .utf8 = "@",
.unshifted_codepoint = '2', .unshifted_codepoint = '2',
@ -2005,7 +2005,7 @@ test "legacy: ctrl+shift+letter ascii" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
{ {
var enc: KeyEncoder = .{ .event = .{ var enc: KeyEncoder = .{ .event = .{
.key = .m, .key = .key_m,
.mods = .{ .ctrl = true, .shift = true }, .mods = .{ .ctrl = true, .shift = true },
.utf8 = "M", .utf8 = "M",
.unshifted_codepoint = 'm', .unshifted_codepoint = 'm',
@ -2019,7 +2019,7 @@ test "legacy: shift+function key should use all mods" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.key = .up, .key = .arrow_up,
.mods = .{ .shift = true }, .mods = .{ .shift = true },
.consumed_mods = .{ .shift = true }, .consumed_mods = .{ .shift = true },
}, },
@ -2033,7 +2033,7 @@ test "legacy: keypad enter" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.key = .kp_enter, .key = .numpad_enter,
.mods = .{}, .mods = .{},
.consumed_mods = .{}, .consumed_mods = .{},
}, },
@ -2047,7 +2047,7 @@ test "legacy: keypad 1" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.key = .kp_1, .key = .numpad_1,
.mods = .{}, .mods = .{},
.consumed_mods = .{}, .consumed_mods = .{},
.utf8 = "1", .utf8 = "1",
@ -2062,7 +2062,7 @@ test "legacy: keypad 1 with application keypad" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.key = .kp_1, .key = .numpad_1,
.mods = .{}, .mods = .{},
.consumed_mods = .{}, .consumed_mods = .{},
.utf8 = "1", .utf8 = "1",
@ -2078,7 +2078,7 @@ test "legacy: keypad 1 with application keypad and numlock" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.key = .kp_1, .key = .numpad_1,
.mods = .{ .num_lock = true }, .mods = .{ .num_lock = true },
.consumed_mods = .{}, .consumed_mods = .{},
.utf8 = "1", .utf8 = "1",
@ -2094,7 +2094,7 @@ test "legacy: keypad 1 with application keypad and numlock ignore" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.key = .kp_1, .key = .numpad_1,
.mods = .{ .num_lock = false }, .mods = .{ .num_lock = false },
.consumed_mods = .{}, .consumed_mods = .{},
.utf8 = "1", .utf8 = "1",
@ -2189,8 +2189,8 @@ test "legacy: hu layout ctrl+ő sends proper codepoint" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.key = .left_bracket, .key = .bracket_left,
.physical_key = .left_bracket, .physical_key = .bracket_left,
.mods = .{ .ctrl = true }, .mods = .{ .ctrl = true },
.utf8 = "ő", .utf8 = "ő",
.unshifted_codepoint = 337, .unshifted_codepoint = 337,
@ -2207,7 +2207,7 @@ test "legacy: super-only on macOS with text" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.key = .b, .key = .key_b,
.utf8 = "b", .utf8 = "b",
.mods = .{ .super = true }, .mods = .{ .super = true },
}, },
@ -2223,7 +2223,7 @@ test "legacy: super and other mods on macOS with text" {
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{ var enc: KeyEncoder = .{
.event = .{ .event = .{
.key = .b, .key = .key_b,
.utf8 = "B", .utf8 = "B",
.mods = .{ .super = true, .shift = true }, .mods = .{ .super = true, .shift = true },
}, },
@ -2234,50 +2234,50 @@ test "legacy: super and other mods on macOS with text" {
} }
test "ctrlseq: normal ctrl c" { test "ctrlseq: normal ctrl c" {
const seq = ctrlSeq(.invalid, "c", 'c', .{ .ctrl = true }); const seq = ctrlSeq(.unidentified, "c", 'c', .{ .ctrl = true });
try testing.expectEqual(@as(u8, 0x03), seq.?); try testing.expectEqual(@as(u8, 0x03), seq.?);
} }
test "ctrlseq: normal ctrl c, right control" { test "ctrlseq: normal ctrl c, right control" {
const seq = ctrlSeq(.invalid, "c", 'c', .{ .ctrl = true, .sides = .{ .ctrl = .right } }); const seq = ctrlSeq(.unidentified, "c", 'c', .{ .ctrl = true, .sides = .{ .ctrl = .right } });
try testing.expectEqual(@as(u8, 0x03), seq.?); try testing.expectEqual(@as(u8, 0x03), seq.?);
} }
test "ctrlseq: alt should be allowed" { test "ctrlseq: alt should be allowed" {
const seq = ctrlSeq(.invalid, "c", 'c', .{ .alt = true, .ctrl = true }); const seq = ctrlSeq(.unidentified, "c", 'c', .{ .alt = true, .ctrl = true });
try testing.expectEqual(@as(u8, 0x03), seq.?); try testing.expectEqual(@as(u8, 0x03), seq.?);
} }
test "ctrlseq: no ctrl does nothing" { test "ctrlseq: no ctrl does nothing" {
try testing.expect(ctrlSeq(.invalid, "c", 'c', .{}) == null); try testing.expect(ctrlSeq(.unidentified, "c", 'c', .{}) == null);
} }
test "ctrlseq: shifted non-character" { test "ctrlseq: shifted non-character" {
const seq = ctrlSeq(.invalid, "_", '-', .{ .ctrl = true, .shift = true }); const seq = ctrlSeq(.unidentified, "_", '-', .{ .ctrl = true, .shift = true });
try testing.expectEqual(@as(u8, 0x1F), seq.?); try testing.expectEqual(@as(u8, 0x1F), seq.?);
} }
test "ctrlseq: caps ascii letter" { test "ctrlseq: caps ascii letter" {
const seq = ctrlSeq(.invalid, "C", 'c', .{ .ctrl = true, .caps_lock = true }); const seq = ctrlSeq(.unidentified, "C", 'c', .{ .ctrl = true, .caps_lock = true });
try testing.expectEqual(@as(u8, 0x03), seq.?); try testing.expectEqual(@as(u8, 0x03), seq.?);
} }
test "ctrlseq: shift does not generate ctrl seq" { test "ctrlseq: shift does not generate ctrl seq" {
try testing.expect(ctrlSeq(.invalid, "C", 'c', .{ .shift = true }) == null); try testing.expect(ctrlSeq(.unidentified, "C", 'c', .{ .shift = true }) == null);
try testing.expect(ctrlSeq(.invalid, "C", 'c', .{ .shift = true, .ctrl = true }) == null); try testing.expect(ctrlSeq(.unidentified, "C", 'c', .{ .shift = true, .ctrl = true }) == null);
} }
test "ctrlseq: russian ctrl c" { test "ctrlseq: russian ctrl c" {
const seq = ctrlSeq(.c, "с", 0x0441, .{ .ctrl = true }); const seq = ctrlSeq(.key_c, "с", 0x0441, .{ .ctrl = true });
try testing.expectEqual(@as(u8, 0x03), seq.?); try testing.expectEqual(@as(u8, 0x03), seq.?);
} }
test "ctrlseq: russian shifted ctrl c" { test "ctrlseq: russian shifted ctrl c" {
const seq = ctrlSeq(.c, "с", 0x0441, .{ .ctrl = true, .shift = true }); const seq = ctrlSeq(.key_c, "с", 0x0441, .{ .ctrl = true, .shift = true });
try testing.expect(seq == null); try testing.expect(seq == null);
} }
test "ctrlseq: russian alt ctrl c" { test "ctrlseq: russian alt ctrl c" {
const seq = ctrlSeq(.c, "с", 0x0441, .{ .ctrl = true, .alt = true }); const seq = ctrlSeq(.key_c, "с", 0x0441, .{ .ctrl = true, .alt = true });
try testing.expectEqual(@as(u8, 0x03), seq.?); try testing.expectEqual(@as(u8, 0x03), seq.?);
} }

View File

@ -75,10 +75,10 @@ pub const KeyEntryArray = std.EnumArray(key.Key, []const Entry);
pub const keys = keys: { pub const keys = keys: {
var result = KeyEntryArray.initFill(&.{}); var result = KeyEntryArray.initFill(&.{});
result.set(.up, pcStyle("\x1b[1;{}A") ++ cursorKey("\x1b[A", "\x1bOA")); result.set(.arrow_up, pcStyle("\x1b[1;{}A") ++ cursorKey("\x1b[A", "\x1bOA"));
result.set(.down, pcStyle("\x1b[1;{}B") ++ cursorKey("\x1b[B", "\x1bOB")); result.set(.arrow_down, pcStyle("\x1b[1;{}B") ++ cursorKey("\x1b[B", "\x1bOB"));
result.set(.right, pcStyle("\x1b[1;{}C") ++ cursorKey("\x1b[C", "\x1bOC")); result.set(.arrow_right, pcStyle("\x1b[1;{}C") ++ cursorKey("\x1b[C", "\x1bOC"));
result.set(.left, pcStyle("\x1b[1;{}D") ++ cursorKey("\x1b[D", "\x1bOD")); result.set(.arrow_left, pcStyle("\x1b[1;{}D") ++ cursorKey("\x1b[D", "\x1bOD"));
result.set(.home, pcStyle("\x1b[1;{}H") ++ cursorKey("\x1b[H", "\x1bOH")); result.set(.home, pcStyle("\x1b[1;{}H") ++ cursorKey("\x1b[H", "\x1bOH"));
result.set(.end, pcStyle("\x1b[1;{}F") ++ cursorKey("\x1b[F", "\x1bOF")); result.set(.end, pcStyle("\x1b[1;{}F") ++ cursorKey("\x1b[F", "\x1bOF"));
result.set(.insert, pcStyle("\x1b[2;{}~") ++ .{Entry{ .sequence = "\x1B[2~" }}); result.set(.insert, pcStyle("\x1b[2;{}~") ++ .{Entry{ .sequence = "\x1B[2~" }});
@ -101,33 +101,33 @@ pub const keys = keys: {
result.set(.f12, pcStyle("\x1b[24;{}~") ++ .{Entry{ .sequence = "\x1B[24~" }}); result.set(.f12, pcStyle("\x1b[24;{}~") ++ .{Entry{ .sequence = "\x1B[24~" }});
// Keypad keys // Keypad keys
result.set(.kp_0, kpKeys("p")); result.set(.numpad_0, kpKeys("p"));
result.set(.kp_1, kpKeys("q")); result.set(.numpad_1, kpKeys("q"));
result.set(.kp_2, kpKeys("r")); result.set(.numpad_2, kpKeys("r"));
result.set(.kp_3, kpKeys("s")); result.set(.numpad_3, kpKeys("s"));
result.set(.kp_4, kpKeys("t")); result.set(.numpad_4, kpKeys("t"));
result.set(.kp_5, kpKeys("u")); result.set(.numpad_5, kpKeys("u"));
result.set(.kp_6, kpKeys("v")); result.set(.numpad_6, kpKeys("v"));
result.set(.kp_7, kpKeys("w")); result.set(.numpad_7, kpKeys("w"));
result.set(.kp_8, kpKeys("x")); result.set(.numpad_8, kpKeys("x"));
result.set(.kp_9, kpKeys("y")); result.set(.numpad_9, kpKeys("y"));
result.set(.kp_decimal, kpKeys("n")); result.set(.numpad_decimal, kpKeys("n"));
result.set(.kp_divide, kpKeys("o")); result.set(.numpad_divide, kpKeys("o"));
result.set(.kp_multiply, kpKeys("j")); result.set(.numpad_multiply, kpKeys("j"));
result.set(.kp_subtract, kpKeys("m")); result.set(.numpad_subtract, kpKeys("m"));
result.set(.kp_add, kpKeys("k")); result.set(.numpad_add, kpKeys("k"));
result.set(.kp_enter, kpKeys("M") ++ .{Entry{ .sequence = "\r" }}); result.set(.numpad_enter, kpKeys("M") ++ .{Entry{ .sequence = "\r" }});
result.set(.kp_up, pcStyle("\x1b[1;{}A") ++ cursorKey("\x1b[A", "\x1bOA")); result.set(.numpad_up, pcStyle("\x1b[1;{}A") ++ cursorKey("\x1b[A", "\x1bOA"));
result.set(.kp_down, pcStyle("\x1b[1;{}B") ++ cursorKey("\x1b[B", "\x1bOB")); result.set(.numpad_down, pcStyle("\x1b[1;{}B") ++ cursorKey("\x1b[B", "\x1bOB"));
result.set(.kp_right, pcStyle("\x1b[1;{}C") ++ cursorKey("\x1b[C", "\x1bOC")); result.set(.numpad_right, pcStyle("\x1b[1;{}C") ++ cursorKey("\x1b[C", "\x1bOC"));
result.set(.kp_left, pcStyle("\x1b[1;{}D") ++ cursorKey("\x1b[D", "\x1bOD")); result.set(.numpad_left, pcStyle("\x1b[1;{}D") ++ cursorKey("\x1b[D", "\x1bOD"));
result.set(.kp_begin, pcStyle("\x1b[1;{}E") ++ cursorKey("\x1b[E", "\x1bOE")); result.set(.numpad_begin, pcStyle("\x1b[1;{}E") ++ cursorKey("\x1b[E", "\x1bOE"));
result.set(.kp_home, pcStyle("\x1b[1;{}H") ++ cursorKey("\x1b[H", "\x1bOH")); result.set(.numpad_home, pcStyle("\x1b[1;{}H") ++ cursorKey("\x1b[H", "\x1bOH"));
result.set(.kp_end, pcStyle("\x1b[1;{}F") ++ cursorKey("\x1b[F", "\x1bOF")); result.set(.numpad_end, pcStyle("\x1b[1;{}F") ++ cursorKey("\x1b[F", "\x1bOF"));
result.set(.kp_insert, pcStyle("\x1b[2;{}~") ++ .{Entry{ .sequence = "\x1B[2~" }}); result.set(.numpad_insert, pcStyle("\x1b[2;{}~") ++ .{Entry{ .sequence = "\x1B[2~" }});
result.set(.kp_delete, pcStyle("\x1b[3;{}~") ++ .{Entry{ .sequence = "\x1B[3~" }}); result.set(.numpad_delete, pcStyle("\x1b[3;{}~") ++ .{Entry{ .sequence = "\x1B[3~" }});
result.set(.kp_page_up, pcStyle("\x1b[5;{}~") ++ .{Entry{ .sequence = "\x1B[5~" }}); result.set(.numpad_page_up, pcStyle("\x1b[5;{}~") ++ .{Entry{ .sequence = "\x1B[5~" }});
result.set(.kp_page_down, pcStyle("\x1b[6;{}~") ++ .{Entry{ .sequence = "\x1B[6~" }}); result.set(.numpad_page_down, pcStyle("\x1b[6;{}~") ++ .{Entry{ .sequence = "\x1B[6~" }});
result.set(.backspace, &.{ result.set(.backspace, &.{
// Modify Keys Normal // Modify Keys Normal

View File

@ -21,7 +21,7 @@ pub const KeyEvent = struct {
/// the "i" physical key will be reported as "c". The physical /// the "i" physical key will be reported as "c". The physical
/// key is the key that was physically pressed on the keyboard. /// key is the key that was physically pressed on the keyboard.
key: Key, key: Key,
physical_key: Key = .invalid, physical_key: Key = .unidentified,
/// Mods are the modifiers that are pressed. /// Mods are the modifiers that are pressed.
mods: Mods = .{}, mods: Mods = .{},
@ -391,6 +391,25 @@ pub const Key = enum(c_int) {
numpad_paren_right, numpad_paren_right,
numpad_subtract, numpad_subtract,
// > For numpads that provide keys not listed here, a code value string
// > should be created by starting with "Numpad" and appending an
// > appropriate description of the key.
//
// These numpad entries are distinguished by various encoding protocols
// (legacy and Kitty) so we support them here in case the apprt can
// produce them.
numpad_up,
numpad_down,
numpad_right,
numpad_left,
numpad_begin,
numpad_home,
numpad_end,
numpad_insert,
numpad_delete,
numpad_page_up,
numpad_page_down,
// "Function Section" § 3.5 // "Function Section" § 3.5
escape, escape,
f1, f1,
@ -405,6 +424,19 @@ pub const Key = enum(c_int) {
f10, f10,
f11, f11,
f12, f12,
f13,
f14,
f15,
f16,
f17,
f18,
f19,
f20,
f21,
f22,
f23,
f24,
f25,
@"fn", @"fn",
fn_lock, fn_lock,
print_screen, print_screen,
@ -437,87 +469,61 @@ pub const Key = enum(c_int) {
// Backwards compatibility for Ghostty 1.1.x and earlier, we don't // Backwards compatibility for Ghostty 1.1.x and earlier, we don't
// want to force people to rewrite their configs. // want to force people to rewrite their configs.
pub const a = .key_a; // pub const zero = .digit_0;
pub const b = .key_b; // pub const one = .digit_1;
pub const c = .key_c; // pub const two = .digit_2;
pub const d = .key_d; // pub const three = .digit_3;
pub const e = .key_e; // pub const four = .digit_4;
pub const f = .key_f; // pub const five = .digit_5;
pub const g = .key_g; // pub const six = .digit_6;
pub const h = .key_h; // pub const seven = .digit_7;
pub const i = .key_i; // pub const eight = .digit_8;
pub const j = .key_j; // pub const nine = .digit_9;
pub const k = .key_k; // pub const apostrophe = .quote;
pub const l = .key_l; // pub const grave_accent = .backquote;
pub const m = .key_m; // pub const left_bracket = .bracket_left;
pub const n = .key_n; // pub const right_bracket = .bracket_right;
pub const o = .key_o; // pub const up = .arrow_up;
pub const p = .key_p; // pub const down = .arrow_down;
pub const q = .key_q; // pub const left = .arrow_left;
pub const r = .key_r; // pub const right = .arrow_right;
pub const s = .key_s; // pub const kp_0 = .numpad_0;
pub const t = .key_t; // pub const kp_1 = .numpad_1;
pub const u = .key_u; // pub const kp_2 = .numpad_2;
pub const v = .key_v; // pub const kp_3 = .numpad_3;
pub const w = .key_w; // pub const kp_4 = .numpad_4;
pub const x = .key_x; // pub const kp_5 = .numpad_5;
pub const y = .key_y; // pub const kp_6 = .numpad_6;
pub const z = .key_z; // pub const kp_7 = .numpad_7;
pub const zero = .digit_0; // pub const kp_8 = .numpad_8;
pub const one = .digit_1; // pub const kp_9 = .numpad_9;
pub const two = .digit_2; // pub const kp_decimal = .numpad_decimal;
pub const three = .digit_3; // pub const kp_divide = .numpad_divide;
pub const four = .digit_4; // pub const kp_multiply = .numpad_multiply;
pub const five = .digit_5; // pub const kp_subtract = .numpad_subtract;
pub const six = .digit_6; // pub const kp_add = .numpad_add;
pub const seven = .digit_7; // pub const kp_enter = .numpad_enter;
pub const eight = .digit_8; // pub const kp_equal = .numpad_equal;
pub const nine = .digit_9; // pub const kp_separator = .numpad_separator;
pub const apostrophe = .quote; // pub const kp_left = .numpad_left;
pub const grave_accent = .backquote; // pub const kp_right = .numpad_right;
pub const left_bracket = .bracket_left; // pub const kp_up = .numpad_up;
pub const right_bracket = .bracket_right; // pub const kp_down = .numpad_down;
pub const up = .arrow_up; // pub const kp_page_up = .numpad_page_up;
pub const down = .arrow_down; // pub const kp_page_down = .numpad_page_down;
pub const left = .arrow_left; // pub const kp_home = .numpad_home;
pub const right = .arrow_right; // pub const kp_end = .numpad_end;
pub const kp_0 = .numpad_0; // pub const kp_insert = .numpad_insert;
pub const kp_1 = .numpad_1; // pub const kp_delete = .numpad_delete;
pub const kp_2 = .numpad_2; // pub const kp_begin = .numpad_begin;
pub const kp_3 = .numpad_3; // pub const left_shift = .shift_left;
pub const kp_4 = .numpad_4; // pub const right_shift = .shift_right;
pub const kp_5 = .numpad_5; // pub const left_control = .control_left;
pub const kp_6 = .numpad_6; // pub const right_control = .control_right;
pub const kp_7 = .numpad_7; // pub const left_alt = .alt_left;
pub const kp_8 = .numpad_8; // pub const right_alt = .alt_right;
pub const kp_9 = .numpad_9; // pub const left_super = .meta_left;
pub const kp_decimal = .numpad_decimal; // pub const right_super = .meta_right;
pub const kp_divide = .numpad_divide;
pub const kp_multiply = .numpad_multiply;
pub const kp_subtract = .numpad_subtract;
pub const kp_add = .numpad_add;
pub const kp_enter = .numpad_enter;
pub const kp_equal = .numpad_equal;
pub const kp_separator = .numpad_separator;
pub const kp_left = .numpad_left;
pub const kp_right = .numpad_right;
pub const kp_up = .numpad_up;
pub const kp_down = .numpad_down;
pub const kp_page_up = .numpad_page_up;
pub const kp_page_down = .numpad_page_down;
pub const kp_home = .numpad_home;
pub const kp_end = .numpad_end;
pub const kp_insert = .numpad_insert;
pub const kp_delete = .numpad_delete;
pub const kp_begin = .numpad_begin;
pub const left_shift = .shift_left;
pub const right_shift = .shift_right;
pub const left_control = .control_left;
pub const right_control = .control_right;
pub const left_alt = .alt_left;
pub const right_alt = .alt_right;
pub const left_super = .meta_left;
pub const right_super = .meta_right;
/// Converts an ASCII character to a key, if possible. This returns /// Converts an ASCII character to a key, if possible. This returns
/// null if the character is unknown. /// null if the character is unknown.
@ -586,7 +592,7 @@ pub const Key = enum(c_int) {
return switch (self) { return switch (self) {
inline else => |tag| { inline else => |tag| {
const name = @tagName(tag); const name = @tagName(tag);
const result = comptime std.mem.startsWith(u8, name, "kp_"); const result = comptime std.mem.startsWith(u8, name, "numpad_");
return result; return result;
}, },
}; };
@ -763,107 +769,106 @@ pub const Key = enum(c_int) {
/// or ctrl. /// or ctrl.
pub fn ctrlOrSuper(self: Key) bool { pub fn ctrlOrSuper(self: Key) bool {
if (comptime builtin.target.os.tag.isDarwin()) { if (comptime builtin.target.os.tag.isDarwin()) {
return self == .left_super or self == .right_super; return self == .meta_left or self == .meta_right;
} }
return self == .left_control or self == .right_control; return self == .control_left or self == .control_right;
} }
/// true if this key is either left or right shift. /// true if this key is either left or right shift.
pub fn leftOrRightShift(self: Key) bool { pub fn leftOrRightShift(self: Key) bool {
return self == .left_shift or self == .right_shift; return self == .shift_left or self == .shift_right;
} }
/// true if this key is either left or right alt. /// true if this key is either left or right alt.
pub fn leftOrRightAlt(self: Key) bool { pub fn leftOrRightAlt(self: Key) bool {
return self == .left_alt or self == .right_alt; return self == .alt_left or self == .alt_right;
} }
test "fromASCII should not return keypad keys" { test "fromASCII should not return keypad keys" {
const testing = std.testing; const testing = std.testing;
try testing.expect(Key.fromASCII('0').? == .zero); try testing.expect(Key.fromASCII('0').? == .digit_0);
try testing.expect(Key.fromASCII('*') == null); try testing.expect(Key.fromASCII('*') == null);
} }
test "keypad keys" { test "keypad keys" {
const testing = std.testing; const testing = std.testing;
try testing.expect(Key.kp_0.keypad()); try testing.expect(Key.numpad_0.keypad());
try testing.expect(!Key.one.keypad()); try testing.expect(!Key.digit_1.keypad());
} }
const codepoint_map: []const struct { u21, Key } = &.{ const codepoint_map: []const struct { u21, Key } = &.{
.{ 'a', .a }, .{ 'a', .key_a },
.{ 'b', .b }, .{ 'b', .key_b },
.{ 'c', .c }, .{ 'c', .key_c },
.{ 'd', .d }, .{ 'd', .key_d },
.{ 'e', .e }, .{ 'e', .key_e },
.{ 'f', .f }, .{ 'f', .key_f },
.{ 'g', .g }, .{ 'g', .key_g },
.{ 'h', .h }, .{ 'h', .key_h },
.{ 'i', .i }, .{ 'i', .key_i },
.{ 'j', .j }, .{ 'j', .key_j },
.{ 'k', .k }, .{ 'k', .key_k },
.{ 'l', .l }, .{ 'l', .key_l },
.{ 'm', .m }, .{ 'm', .key_m },
.{ 'n', .n }, .{ 'n', .key_n },
.{ 'o', .o }, .{ 'o', .key_o },
.{ 'p', .p }, .{ 'p', .key_p },
.{ 'q', .q }, .{ 'q', .key_q },
.{ 'r', .r }, .{ 'r', .key_r },
.{ 's', .s }, .{ 's', .key_s },
.{ 't', .t }, .{ 't', .key_t },
.{ 'u', .u }, .{ 'u', .key_u },
.{ 'v', .v }, .{ 'v', .key_v },
.{ 'w', .w }, .{ 'w', .key_w },
.{ 'x', .x }, .{ 'x', .key_x },
.{ 'y', .y }, .{ 'y', .key_y },
.{ 'z', .z }, .{ 'z', .key_z },
.{ '0', .zero }, .{ '0', .digit_0 },
.{ '1', .one }, .{ '1', .digit_1 },
.{ '2', .two }, .{ '2', .digit_2 },
.{ '3', .three }, .{ '3', .digit_3 },
.{ '4', .four }, .{ '4', .digit_4 },
.{ '5', .five }, .{ '5', .digit_5 },
.{ '6', .six }, .{ '6', .digit_6 },
.{ '7', .seven }, .{ '7', .digit_7 },
.{ '8', .eight }, .{ '8', .digit_8 },
.{ '9', .nine }, .{ '9', .digit_9 },
.{ ';', .semicolon }, .{ ';', .semicolon },
.{ ' ', .space }, .{ ' ', .space },
.{ '\'', .apostrophe }, .{ '\'', .quote },
.{ ',', .comma }, .{ ',', .comma },
.{ '`', .grave_accent }, .{ '`', .backquote },
.{ '.', .period }, .{ '.', .period },
.{ '/', .slash }, .{ '/', .slash },
.{ '-', .minus }, .{ '-', .minus },
.{ '+', .plus },
.{ '=', .equal }, .{ '=', .equal },
.{ '[', .left_bracket }, .{ '[', .bracket_left },
.{ ']', .right_bracket }, .{ ']', .bracket_right },
.{ '\\', .backslash }, .{ '\\', .backslash },
// Control characters // Control characters
.{ '\t', .tab }, .{ '\t', .tab },
// Keypad entries. We just assume keypad with the kp_ prefix // Keypad entries. We just assume keypad with the numpad_ prefix
// so that has some special meaning. These must also always be last, // so that has some special meaning. These must also always be last,
// so that our `fromASCII` function doesn't accidentally map them // so that our `fromASCII` function doesn't accidentally map them
// over normal numerics and other keys. // over normal numerics and other keys.
.{ '0', .kp_0 }, .{ '0', .numpad_0 },
.{ '1', .kp_1 }, .{ '1', .numpad_1 },
.{ '2', .kp_2 }, .{ '2', .numpad_2 },
.{ '3', .kp_3 }, .{ '3', .numpad_3 },
.{ '4', .kp_4 }, .{ '4', .numpad_4 },
.{ '5', .kp_5 }, .{ '5', .numpad_5 },
.{ '6', .kp_6 }, .{ '6', .numpad_6 },
.{ '7', .kp_7 }, .{ '7', .numpad_7 },
.{ '8', .kp_8 }, .{ '8', .numpad_8 },
.{ '9', .kp_9 }, .{ '9', .numpad_9 },
.{ '.', .kp_decimal }, .{ '.', .numpad_decimal },
.{ '/', .kp_divide }, .{ '/', .numpad_divide },
.{ '*', .kp_multiply }, .{ '*', .numpad_multiply },
.{ '-', .kp_subtract }, .{ '-', .numpad_subtract },
.{ '+', .kp_add }, .{ '+', .numpad_add },
.{ '=', .kp_equal }, .{ '=', .numpad_equal },
}; };
}; };

View File

@ -49,10 +49,10 @@ const raw_entries: []const RawEntry = &.{
.{ .backspace, 127, 'u', false }, .{ .backspace, 127, 'u', false },
.{ .insert, 2, '~', false }, .{ .insert, 2, '~', false },
.{ .delete, 3, '~', false }, .{ .delete, 3, '~', false },
.{ .left, 1, 'D', false }, .{ .arrow_left, 1, 'D', false },
.{ .right, 1, 'C', false }, .{ .arrow_right, 1, 'C', false },
.{ .up, 1, 'A', false }, .{ .arrow_up, 1, 'A', false },
.{ .down, 1, 'B', false }, .{ .arrow_down, 1, 'B', false },
.{ .page_up, 5, '~', false }, .{ .page_up, 5, '~', false },
.{ .page_down, 6, '~', false }, .{ .page_down, 6, '~', false },
.{ .home, 1, 'H', false }, .{ .home, 1, 'H', false },
@ -89,46 +89,32 @@ const raw_entries: []const RawEntry = &.{
.{ .f24, 57387, 'u', false }, .{ .f24, 57387, 'u', false },
.{ .f25, 57388, 'u', false }, .{ .f25, 57388, 'u', false },
.{ .kp_0, 57399, 'u', false }, .{ .numpad_0, 57399, 'u', false },
.{ .kp_1, 57400, 'u', false }, .{ .numpad_1, 57400, 'u', false },
.{ .kp_2, 57401, 'u', false }, .{ .numpad_2, 57401, 'u', false },
.{ .kp_3, 57402, 'u', false }, .{ .numpad_3, 57402, 'u', false },
.{ .kp_4, 57403, 'u', false }, .{ .numpad_4, 57403, 'u', false },
.{ .kp_5, 57404, 'u', false }, .{ .numpad_5, 57404, 'u', false },
.{ .kp_6, 57405, 'u', false }, .{ .numpad_6, 57405, 'u', false },
.{ .kp_7, 57406, 'u', false }, .{ .numpad_7, 57406, 'u', false },
.{ .kp_8, 57407, 'u', false }, .{ .numpad_8, 57407, 'u', false },
.{ .kp_9, 57408, 'u', false }, .{ .numpad_9, 57408, 'u', false },
.{ .kp_decimal, 57409, 'u', false }, .{ .numpad_decimal, 57409, 'u', false },
.{ .kp_divide, 57410, 'u', false }, .{ .numpad_divide, 57410, 'u', false },
.{ .kp_multiply, 57411, 'u', false }, .{ .numpad_multiply, 57411, 'u', false },
.{ .kp_subtract, 57412, 'u', false }, .{ .numpad_subtract, 57412, 'u', false },
.{ .kp_add, 57413, 'u', false }, .{ .numpad_add, 57413, 'u', false },
.{ .kp_enter, 57414, 'u', false }, .{ .numpad_enter, 57414, 'u', false },
.{ .kp_equal, 57415, 'u', false }, .{ .numpad_equal, 57415, 'u', false },
.{ .kp_separator, 57416, 'u', false },
.{ .kp_left, 57417, 'u', false },
.{ .kp_right, 57418, 'u', false },
.{ .kp_up, 57419, 'u', false },
.{ .kp_down, 57420, 'u', false },
.{ .kp_page_up, 57421, 'u', false },
.{ .kp_page_down, 57422, 'u', false },
.{ .kp_home, 57423, 'u', false },
.{ .kp_end, 57424, 'u', false },
.{ .kp_insert, 57425, 'u', false },
.{ .kp_delete, 57426, 'u', false },
.{ .kp_begin, 57427, 'u', false },
// TODO: media keys .{ .shift_left, 57441, 'u', true },
.{ .shift_right, 57447, 'u', true },
.{ .left_shift, 57441, 'u', true }, .{ .control_left, 57442, 'u', true },
.{ .right_shift, 57447, 'u', true }, .{ .control_right, 57448, 'u', true },
.{ .left_control, 57442, 'u', true }, .{ .meta_left, 57444, 'u', true },
.{ .right_control, 57448, 'u', true }, .{ .meta_right, 57450, 'u', true },
.{ .left_super, 57444, 'u', true }, .{ .alt_left, 57443, 'u', true },
.{ .right_super, 57450, 'u', true }, .{ .alt_right, 57449, 'u', true },
.{ .left_alt, 57443, 'u', true },
.{ .right_alt, 57449, 'u', true },
}; };
test { test {

View File

@ -56,7 +56,7 @@ pub const Event = struct {
// Write our key. If we have an invalid key we attempt to write // Write our key. If we have an invalid key we attempt to write
// the utf8 associated with it if we have it to handle non-ascii. // the utf8 associated with it if we have it to handle non-ascii.
try writer.writeAll(switch (self.event.key) { try writer.writeAll(switch (self.event.key) {
.invalid => if (self.event.utf8.len > 0) self.event.utf8 else @tagName(.invalid), .unidentified => if (self.event.utf8.len > 0) self.event.utf8 else @tagName(self.event.key),
else => @tagName(self.event.key), else => @tagName(self.event.key),
}); });
@ -227,9 +227,9 @@ test "event string" {
const testing = std.testing; const testing = std.testing;
const alloc = testing.allocator; const alloc = testing.allocator;
var event = try Event.init(alloc, .{ .key = .a }); var event = try Event.init(alloc, .{ .key = .key_a });
defer event.deinit(alloc); defer event.deinit(alloc);
var buf: [1024]u8 = undefined; var buf: [1024]u8 = undefined;
try testing.expectEqualStrings("Press: a", try event.label(&buf)); try testing.expectEqualStrings("Press: key_a", try event.label(&buf));
} }

View File

@ -132,7 +132,7 @@ test "keyToMouseShape" {
{ {
// No specific key pressed // No specific key pressed
const m: SurfaceMouse = .{ const m: SurfaceMouse = .{
.physical_key = .invalid, .physical_key = .unidentified,
.mouse_event = .none, .mouse_event = .none,
.mouse_shape = .progress, .mouse_shape = .progress,
.mods = .{}, .mods = .{},
@ -148,7 +148,7 @@ test "keyToMouseShape" {
// Over a link. NOTE: This tests that we don't touch the inbound state, // Over a link. NOTE: This tests that we don't touch the inbound state,
// not necessarily if we're over a link. // not necessarily if we're over a link.
const m: SurfaceMouse = .{ const m: SurfaceMouse = .{
.physical_key = .left_shift, .physical_key = .shift_left,
.mouse_event = .none, .mouse_event = .none,
.mouse_shape = .progress, .mouse_shape = .progress,
.mods = .{}, .mods = .{},
@ -163,7 +163,7 @@ test "keyToMouseShape" {
{ {
// Mouse is currently hidden // Mouse is currently hidden
const m: SurfaceMouse = .{ const m: SurfaceMouse = .{
.physical_key = .left_shift, .physical_key = .shift_left,
.mouse_event = .none, .mouse_event = .none,
.mouse_shape = .progress, .mouse_shape = .progress,
.mods = .{}, .mods = .{},
@ -178,7 +178,7 @@ test "keyToMouseShape" {
{ {
// default, no mods (mouse tracking) // default, no mods (mouse tracking)
const m: SurfaceMouse = .{ const m: SurfaceMouse = .{
.physical_key = .left_shift, .physical_key = .shift_left,
.mouse_event = .x10, .mouse_event = .x10,
.mouse_shape = .default, .mouse_shape = .default,
.mods = .{}, .mods = .{},
@ -194,7 +194,7 @@ test "keyToMouseShape" {
{ {
// default -> crosshair (mouse tracking) // default -> crosshair (mouse tracking)
const m: SurfaceMouse = .{ const m: SurfaceMouse = .{
.physical_key = .left_alt, .physical_key = .alt_left,
.mouse_event = .x10, .mouse_event = .x10,
.mouse_shape = .default, .mouse_shape = .default,
.mods = .{ .ctrl = true, .super = true, .alt = true, .shift = true }, .mods = .{ .ctrl = true, .super = true, .alt = true, .shift = true },
@ -210,7 +210,7 @@ test "keyToMouseShape" {
{ {
// default -> text (mouse tracking) // default -> text (mouse tracking)
const m: SurfaceMouse = .{ const m: SurfaceMouse = .{
.physical_key = .left_shift, .physical_key = .shift_left,
.mouse_event = .x10, .mouse_event = .x10,
.mouse_shape = .default, .mouse_shape = .default,
.mods = .{ .shift = true }, .mods = .{ .shift = true },
@ -226,7 +226,7 @@ test "keyToMouseShape" {
{ {
// crosshair -> text (mouse tracking) // crosshair -> text (mouse tracking)
const m: SurfaceMouse = .{ const m: SurfaceMouse = .{
.physical_key = .left_alt, .physical_key = .alt_left,
.mouse_event = .x10, .mouse_event = .x10,
.mouse_shape = .crosshair, .mouse_shape = .crosshair,
.mods = .{ .shift = true }, .mods = .{ .shift = true },
@ -242,7 +242,7 @@ test "keyToMouseShape" {
{ {
// crosshair -> default (mouse tracking) // crosshair -> default (mouse tracking)
const m: SurfaceMouse = .{ const m: SurfaceMouse = .{
.physical_key = .left_alt, .physical_key = .alt_left,
.mouse_event = .x10, .mouse_event = .x10,
.mouse_shape = .crosshair, .mouse_shape = .crosshair,
.mods = .{}, .mods = .{},
@ -258,7 +258,7 @@ test "keyToMouseShape" {
{ {
// text -> crosshair (mouse tracking) // text -> crosshair (mouse tracking)
const m: SurfaceMouse = .{ const m: SurfaceMouse = .{
.physical_key = .left_alt, .physical_key = .alt_left,
.mouse_event = .x10, .mouse_event = .x10,
.mouse_shape = .text, .mouse_shape = .text,
.mods = .{ .ctrl = true, .super = true, .alt = true, .shift = true }, .mods = .{ .ctrl = true, .super = true, .alt = true, .shift = true },
@ -274,7 +274,7 @@ test "keyToMouseShape" {
{ {
// text -> default (mouse tracking) // text -> default (mouse tracking)
const m: SurfaceMouse = .{ const m: SurfaceMouse = .{
.physical_key = .left_shift, .physical_key = .shift_left,
.mouse_event = .x10, .mouse_event = .x10,
.mouse_shape = .text, .mouse_shape = .text,
.mods = .{}, .mods = .{},
@ -290,7 +290,7 @@ test "keyToMouseShape" {
{ {
// text, no mods (no mouse tracking) // text, no mods (no mouse tracking)
const m: SurfaceMouse = .{ const m: SurfaceMouse = .{
.physical_key = .left_shift, .physical_key = .shift_left,
.mouse_event = .none, .mouse_event = .none,
.mouse_shape = .text, .mouse_shape = .text,
.mods = .{}, .mods = .{},
@ -306,7 +306,7 @@ test "keyToMouseShape" {
{ {
// text -> crosshair (no mouse tracking) // text -> crosshair (no mouse tracking)
const m: SurfaceMouse = .{ const m: SurfaceMouse = .{
.physical_key = .left_alt, .physical_key = .alt_left,
.mouse_event = .none, .mouse_event = .none,
.mouse_shape = .text, .mouse_shape = .text,
.mods = .{ .ctrl = true, .super = true, .alt = true }, .mods = .{ .ctrl = true, .super = true, .alt = true },
@ -322,7 +322,7 @@ test "keyToMouseShape" {
{ {
// crosshair -> text (no mouse tracking) // crosshair -> text (no mouse tracking)
const m: SurfaceMouse = .{ const m: SurfaceMouse = .{
.physical_key = .left_alt, .physical_key = .alt_left,
.mouse_event = .none, .mouse_event = .none,
.mouse_shape = .crosshair, .mouse_shape = .crosshair,
.mods = .{}, .mods = .{},