apprt: implement key_sequence action

This commit is contained in:
Mitchell Hashimoto
2024-10-08 06:51:25 -10:00
parent 8d7367fa64
commit 5c1ffbb642
7 changed files with 62 additions and 0 deletions

View File

@ -500,6 +500,12 @@ typedef enum {
GHOSTTY_RENDERER_HEALTH_UNHEALTHY, GHOSTTY_RENDERER_HEALTH_UNHEALTHY,
} ghostty_action_renderer_health_e; } ghostty_action_renderer_health_e;
// apprt.action.KeySequence
typedef struct {
bool active;
ghostty_input_trigger_s trigger;
} ghostty_action_key_sequence_s;
// apprt.Action.Key // apprt.Action.Key
typedef enum { typedef enum {
GHOSTTY_ACTION_NEW_WINDOW, GHOSTTY_ACTION_NEW_WINDOW,
@ -531,6 +537,7 @@ typedef enum {
GHOSTTY_ACTION_OPEN_CONFIG, GHOSTTY_ACTION_OPEN_CONFIG,
GHOSTTY_ACTION_QUIT_TIMER, GHOSTTY_ACTION_QUIT_TIMER,
GHOSTTY_ACTION_SECURE_INPUT, GHOSTTY_ACTION_SECURE_INPUT,
GHOSTTY_ACTION_KEY_SEQUENCE,
} ghostty_action_tag_e; } ghostty_action_tag_e;
typedef union { typedef union {
@ -551,6 +558,7 @@ typedef union {
ghostty_action_renderer_health_e renderer_health; ghostty_action_renderer_health_e renderer_health;
ghostty_action_quit_timer_e quit_timer; ghostty_action_quit_timer_e quit_timer;
ghostty_action_secure_input_e secure_input; ghostty_action_secure_input_e secure_input;
ghostty_action_key_sequence_s key_sequence;
} ghostty_action_u; } ghostty_action_u;
typedef struct { typedef struct {

View File

@ -515,6 +515,8 @@ extension Ghostty {
case GHOSTTY_ACTION_TOGGLE_VISIBILITY: case GHOSTTY_ACTION_TOGGLE_VISIBILITY:
toggleVisibility(app, target: target) toggleVisibility(app, target: target)
case GHOSTTY_ACTION_KEY_SEQUENCE:
fallthrough
case GHOSTTY_ACTION_CLOSE_ALL_WINDOWS: case GHOSTTY_ACTION_CLOSE_ALL_WINDOWS:
fallthrough fallthrough
case GHOSTTY_ACTION_TOGGLE_TAB_OVERVIEW: case GHOSTTY_ACTION_TOGGLE_TAB_OVERVIEW:

View File

@ -1709,6 +1709,18 @@ fn maybeHandleBinding(
try self.keyboard.queued.append(self.alloc, req); try self.keyboard.queued.append(self.alloc, req);
} }
// Start or continue our key sequence
self.rt_app.performAction(
.{ .surface = self },
.key_sequence,
.{ .trigger = entry.key_ptr.* },
) catch |err| {
log.warn(
"failed to notify app of key sequence err={}",
.{err},
);
};
return .consumed; return .consumed;
}, },
@ -1795,6 +1807,18 @@ fn endKeySequence(
action: KeySequenceQueued, action: KeySequenceQueued,
mem: KeySequenceMemory, mem: KeySequenceMemory,
) void { ) void {
// Notify apprt key sequence ended
self.rt_app.performAction(
.{ .surface = self },
.key_sequence,
.end,
) catch |err| {
log.warn(
"failed to notify app of key sequence end err={}",
.{err},
);
};
if (self.keyboard.queued.items.len > 0) { if (self.keyboard.queued.items.len > 0) {
switch (action) { switch (action) {
.flush => for (self.keyboard.queued.items) |write_req| { .flush => for (self.keyboard.queued.items) |write_req| {

View File

@ -1,6 +1,7 @@
const std = @import("std"); const std = @import("std");
const assert = std.debug.assert; const assert = std.debug.assert;
const apprt = @import("../apprt.zig"); const apprt = @import("../apprt.zig");
const input = @import("../input.zig");
const renderer = @import("../renderer.zig"); const renderer = @import("../renderer.zig");
const terminal = @import("../terminal/main.zig"); const terminal = @import("../terminal/main.zig");
const CoreSurface = @import("../Surface.zig"); const CoreSurface = @import("../Surface.zig");
@ -173,6 +174,11 @@ pub const Action = union(Key) {
/// system APIs to not log the input, etc. /// system APIs to not log the input, etc.
secure_input: SecureInput, secure_input: SecureInput,
/// A sequenced key binding has started, continued, or stopped.
/// The UI should show some indication that the user is in a sequenced
/// key mode because other input may be ignored.
key_sequence: KeySequence,
/// Sync with: ghostty_action_tag_e /// Sync with: ghostty_action_tag_e
pub const Key = enum(c_int) { pub const Key = enum(c_int) {
new_window, new_window,
@ -204,6 +210,7 @@ pub const Action = union(Key) {
open_config, open_config,
quit_timer, quit_timer,
secure_input, secure_input,
key_sequence,
}; };
/// Sync with: ghostty_action_u /// Sync with: ghostty_action_u
@ -411,3 +418,21 @@ pub const DesktopNotification = struct {
}; };
} }
}; };
pub const KeySequence = union(enum) {
trigger: input.Trigger,
end,
// Sync with: ghostty_action_key_sequence_s
pub const C = extern struct {
active: bool,
trigger: input.Trigger.C,
};
pub fn cval(self: KeySequence) C {
return switch (self) {
.trigger => |t| .{ .active = true, .trigger = t.cval() },
.end => .{ .active = false, .trigger = .{} },
};
}
};

View File

@ -203,6 +203,7 @@ pub const App = struct {
.render_inspector, .render_inspector,
.quit_timer, .quit_timer,
.secure_input, .secure_input,
.key_sequence,
.desktop_notification, .desktop_notification,
.mouse_over_link, .mouse_over_link,
.cell_size, .cell_size,

View File

@ -411,6 +411,7 @@ pub fn performAction(
.size_limit, .size_limit,
.cell_size, .cell_size,
.secure_input, .secure_input,
.key_sequence,
.render_inspector, .render_inspector,
.renderer_health, .renderer_health,
=> log.warn("unimplemented action={}", .{action}), => log.warn("unimplemented action={}", .{action}),

View File

@ -23,6 +23,7 @@ pub const MousePressureStage = mouse.PressureStage;
pub const ScrollMods = mouse.ScrollMods; pub const ScrollMods = mouse.ScrollMods;
pub const SplitFocusDirection = Binding.Action.SplitFocusDirection; pub const SplitFocusDirection = Binding.Action.SplitFocusDirection;
pub const SplitResizeDirection = Binding.Action.SplitResizeDirection; pub const SplitResizeDirection = Binding.Action.SplitResizeDirection;
pub const Trigger = Binding.Trigger;
// Keymap is only available on macOS right now. We could implement it // Keymap is only available on macOS right now. We could implement it
// in theory for XKB too on Linux but we don't need it right now. // in theory for XKB too on Linux but we don't need it right now.