diff --git a/include/ghostty.h b/include/ghostty.h index 736c7546b..48915b179 100644 --- a/include/ghostty.h +++ b/include/ghostty.h @@ -691,6 +691,27 @@ typedef struct { ghostty_input_trigger_s trigger; } ghostty_action_key_sequence_s; +// apprt.action.KeyTable.Tag +typedef enum { + GHOSTTY_KEY_TABLE_ACTIVATE, + GHOSTTY_KEY_TABLE_DEACTIVATE, + GHOSTTY_KEY_TABLE_DEACTIVATE_ALL, +} ghostty_action_key_table_tag_e; + +// apprt.action.KeyTable.CValue +typedef union { + struct { + const char *name; + size_t len; + } activate; +} ghostty_action_key_table_u; + +// apprt.action.KeyTable.C +typedef struct { + ghostty_action_key_table_tag_e tag; + ghostty_action_key_table_u value; +} ghostty_action_key_table_s; + // apprt.action.ColorKind typedef enum { GHOSTTY_ACTION_COLOR_KIND_FOREGROUND = -1, @@ -836,6 +857,7 @@ typedef enum { GHOSTTY_ACTION_FLOAT_WINDOW, GHOSTTY_ACTION_SECURE_INPUT, GHOSTTY_ACTION_KEY_SEQUENCE, + GHOSTTY_ACTION_KEY_TABLE, GHOSTTY_ACTION_COLOR_CHANGE, GHOSTTY_ACTION_RELOAD_CONFIG, GHOSTTY_ACTION_CONFIG_CHANGE, @@ -881,6 +903,7 @@ typedef union { ghostty_action_float_window_e float_window; ghostty_action_secure_input_e secure_input; ghostty_action_key_sequence_s key_sequence; + ghostty_action_key_table_s key_table; ghostty_action_color_change_s color_change; ghostty_action_reload_config_s reload_config; ghostty_action_config_change_s config_change; diff --git a/src/Surface.zig b/src/Surface.zig index af7cdf136..3a83c704a 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -5631,28 +5631,68 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool .once = tag == .activate_key_table_once, }); + // Notify the UI. + _ = self.rt_app.performAction( + .{ .surface = self }, + .key_table, + .{ .activate = name }, + ) catch |err| { + log.warn( + "failed to notify app of key table err={}", + .{err}, + ); + }; + log.debug("key table activated: {s}", .{name}); }, - .deactivate_key_table => switch (self.keyboard.table_stack.items.len) { - // No key table active. This does nothing. - 0 => return false, + .deactivate_key_table => { + switch (self.keyboard.table_stack.items.len) { + // No key table active. This does nothing. + 0 => return false, - // Final key table active, clear our state. - 1 => self.keyboard.table_stack.clearAndFree(self.alloc), + // Final key table active, clear our state. + 1 => self.keyboard.table_stack.clearAndFree(self.alloc), - // Restore the prior key table. We don't free any memory in - // this case because we assume it will be freed later when - // we finish our key table. - else => _ = self.keyboard.table_stack.pop(), + // Restore the prior key table. We don't free any memory in + // this case because we assume it will be freed later when + // we finish our key table. + else => _ = self.keyboard.table_stack.pop(), + } + + // Notify the UI. + _ = self.rt_app.performAction( + .{ .surface = self }, + .key_table, + .deactivate, + ) catch |err| { + log.warn( + "failed to notify app of key table err={}", + .{err}, + ); + }; }, - .deactivate_all_key_tables => switch (self.keyboard.table_stack.items.len) { - // No key table active. This does nothing. - 0 => return false, + .deactivate_all_key_tables => { + switch (self.keyboard.table_stack.items.len) { + // No key table active. This does nothing. + 0 => return false, - // Clear the entire table stack. - else => self.keyboard.table_stack.clearAndFree(self.alloc), + // Clear the entire table stack. + else => self.keyboard.table_stack.clearAndFree(self.alloc), + } + + // Notify the UI. + _ = self.rt_app.performAction( + .{ .surface = self }, + .key_table, + .deactivate_all, + ) catch |err| { + log.warn( + "failed to notify app of key table err={}", + .{err}, + ); + }; }, .crash => |location| switch (location) { diff --git a/src/apprt/action.zig b/src/apprt/action.zig index 8e0a9d018..25fc6f08a 100644 --- a/src/apprt/action.zig +++ b/src/apprt/action.zig @@ -250,6 +250,9 @@ pub const Action = union(Key) { /// key mode because other input may be ignored. key_sequence: KeySequence, + /// A key table has been activated or deactivated. + key_table: KeyTable, + /// A terminal color was changed programmatically through things /// such as OSC 10/11. color_change: ColorChange, @@ -371,6 +374,7 @@ pub const Action = union(Key) { float_window, secure_input, key_sequence, + key_table, color_change, reload_config, config_change, @@ -711,6 +715,50 @@ pub const KeySequence = union(enum) { } }; +pub const KeyTable = union(enum) { + activate: []const u8, + deactivate, + deactivate_all, + + // Sync with: ghostty_action_key_table_tag_e + pub const Tag = enum(c_int) { + activate, + deactivate, + deactivate_all, + }; + + // Sync with: ghostty_action_key_table_u + pub const CValue = extern union { + activate: extern struct { + name: [*]const u8, + len: usize, + }, + }; + + // Sync with: ghostty_action_key_table_s + pub const C = extern struct { + tag: Tag, + value: CValue, + }; + + pub fn cval(self: KeyTable) C { + return switch (self) { + .activate => |name| .{ + .tag = .activate, + .value = .{ .activate = .{ .name = name.ptr, .len = name.len } }, + }, + .deactivate => .{ + .tag = .deactivate, + .value = undefined, + }, + .deactivate_all => .{ + .tag = .deactivate_all, + .value = undefined, + }, + }; + } +}; + pub const ColorChange = extern struct { kind: ColorKind, r: u8, diff --git a/src/apprt/gtk/class/application.zig b/src/apprt/gtk/class/application.zig index be0f3f2c8..1c0863f3c 100644 --- a/src/apprt/gtk/class/application.zig +++ b/src/apprt/gtk/class/application.zig @@ -744,6 +744,7 @@ pub const Application = extern struct { .toggle_background_opacity, .cell_size, .key_sequence, + .key_table, .render_inspector, .renderer_health, .color_change,