From ffdf86374a964dba28ca2998e914c0eece13a394 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 8 May 2025 11:18:03 -0700 Subject: [PATCH] apprt/gtk: build --- include/ghostty.h | 1 + src/apprt/gtk/Surface.zig | 54 +---------- src/apprt/gtk/key.zig | 184 +++++++++++++++++++------------------- src/config/Config.zig | 43 ++++----- src/input/key.zig | 2 + 5 files changed, 118 insertions(+), 166 deletions(-) diff --git a/include/ghostty.h b/include/ghostty.h index 600396a84..2734fc368 100644 --- a/include/ghostty.h +++ b/include/ghostty.h @@ -222,6 +222,7 @@ typedef enum { GHOSTTY_KEY_NUMPAD_PAREN_LEFT, GHOSTTY_KEY_NUMPAD_PAREN_RIGHT, GHOSTTY_KEY_NUMPAD_SUBTRACT, + GHOSTTY_KEY_NUMPAD_SEPARATOR, GHOSTTY_KEY_NUMPAD_UP, GHOSTTY_KEY_NUMPAD_DOWN, GHOSTTY_KEY_NUMPAD_RIGHT, diff --git a/src/apprt/gtk/Surface.zig b/src/apprt/gtk/Surface.zig index 7ff96480e..a04372494 100644 --- a/src/apprt/gtk/Surface.zig +++ b/src/apprt/gtk/Surface.zig @@ -1840,7 +1840,7 @@ pub fn keyEvent( // (These are keybinds explicitly marked as requesting physical mapping). const physical_key = keycode: for (input.keycodes.entries) |entry| { if (entry.native == keycode) break :keycode entry.key; - } else .invalid; + } else .unidentified; // Get our modifier for the event const mods: input.Mods = gtk_key.eventMods( @@ -1861,52 +1861,6 @@ pub fn keyEvent( break :consumed gtk_key.translateMods(@bitCast(masked)); }; - // If we're not in a dead key state, we want to translate our text - // to some input.Key. - const key = if (!self.im_composing) key: { - // First, try to convert the keyval directly to a key. This allows the - // use of key remapping and identification of keypad numerics (as - // opposed to their ASCII counterparts) - if (gtk_key.keyFromKeyval(keyval)) |key| { - break :key key; - } - - // A completed key. If the length of the key is one then we can - // attempt to translate it to a key enum and call the key - // callback. First try plain ASCII. - if (self.im_len > 0) { - if (input.Key.fromASCII(self.im_buf[0])) |key| { - break :key key; - } - } - - // If that doesn't work then we try to translate the kevval.. - if (keyval_unicode != 0) { - if (std.math.cast(u8, keyval_unicode)) |byte| { - if (input.Key.fromASCII(byte)) |key| { - break :key key; - } - } - } - - // If that doesn't work we use the unshifted value... - if (std.math.cast(u8, keyval_unicode_unshifted)) |ascii| { - if (input.Key.fromASCII(ascii)) |key| { - break :key key; - } - } - - // If we have im text then this is invalid. This means that - // the keypress generated some character that we don't know about - // in our key enum. We don't want to use the physical key because - // it can be simply wrong. For example on "Turkish Q" the "i" key - // on a US layout results in "ı" which is not the same as "i" so - // we shouldn't use the physical key. - if (self.im_len > 0 or keyval_unicode_unshifted != 0) break :key .invalid; - - break :key physical_key; - } else .invalid; - // log.debug("key pressed key={} keyval={x} physical_key={} composing={} text_len={} mods={}", .{ // key, // keyval, @@ -1936,7 +1890,7 @@ pub fn keyEvent( // Invoke the core Ghostty logic to handle this input. const effect = self.core_surface.keyCallback(.{ .action = action, - .key = key, + .key = physical_key, .physical_key = physical_key, .mods = mods, .consumed_mods = consumed_mods, @@ -2088,8 +2042,8 @@ fn gtkInputCommit( // invalid key, which should produce no PTY encoding). _ = self.core_surface.keyCallback(.{ .action = .press, - .key = .invalid, - .physical_key = .invalid, + .key = .unidentified, + .physical_key = .unidentified, .mods = .{}, .consumed_mods = .{}, .composing = false, diff --git a/src/apprt/gtk/key.zig b/src/apprt/gtk/key.zig index 2e00552a6..b3330eb40 100644 --- a/src/apprt/gtk/key.zig +++ b/src/apprt/gtk/key.zig @@ -21,7 +21,7 @@ pub fn accelFromTrigger(buf: []u8, trigger: input.Binding.Trigger) !?[:0]const u // Write our key switch (trigger.key) { - .physical, .translated => |k| { + .physical => |k| { const keyval = keyvalFromKey(k) orelse return null; try writer.writeAll(std.mem.span(gdk.keyvalName(keyval) orelse return null)); }, @@ -122,42 +122,42 @@ pub fn eventMods( // if only the modifier key is pressed, but our core logic // relies on it. switch (physical_key) { - .left_shift => { + .shift_left => { mods.shift = action != .release; mods.sides.shift = .left; }, - .right_shift => { + .shift_right => { mods.shift = action != .release; mods.sides.shift = .right; }, - .left_control => { + .control_left => { mods.ctrl = action != .release; mods.sides.ctrl = .left; }, - .right_control => { + .control_right => { mods.ctrl = action != .release; mods.sides.ctrl = .right; }, - .left_alt => { + .alt_left => { mods.alt = action != .release; mods.sides.alt = .left; }, - .right_alt => { + .alt_right => { mods.alt = action != .release; mods.sides.alt = .right; }, - .left_super => { + .meta_left => { mods.super = action != .release; mods.sides.super = .left; }, - .right_super => { + .meta_right => { mods.super = action != .release; mods.sides.super = .right; }, @@ -182,7 +182,7 @@ pub fn keyvalFromKey(key: input.Key) ?c_uint { switch (key) { inline else => |key_comptime| { return comptime value: { - @setEvalBranchQuota(10_000); + @setEvalBranchQuota(50_000); for (keymap) |entry| { if (entry[1] == key_comptime) break :value entry[0]; } @@ -199,7 +199,7 @@ test "accelFromTrigger" { try testing.expectEqualStrings("q", (try accelFromTrigger(&buf, .{ .mods = .{ .super = true }, - .key = .{ .translated = .q }, + .key = .{ .unicode = 'q' }, })).?); try testing.expectEqualStrings("backslash", (try accelFromTrigger(&buf, .{ @@ -213,61 +213,61 @@ test "accelFromTrigger" { const RawEntry = struct { c_uint, input.Key }; const keymap: []const RawEntry = &.{ - .{ gdk.KEY_a, .a }, - .{ gdk.KEY_b, .b }, - .{ gdk.KEY_c, .c }, - .{ gdk.KEY_d, .d }, - .{ gdk.KEY_e, .e }, - .{ gdk.KEY_f, .f }, - .{ gdk.KEY_g, .g }, - .{ gdk.KEY_h, .h }, - .{ gdk.KEY_i, .i }, - .{ gdk.KEY_j, .j }, - .{ gdk.KEY_k, .k }, - .{ gdk.KEY_l, .l }, - .{ gdk.KEY_m, .m }, - .{ gdk.KEY_n, .n }, - .{ gdk.KEY_o, .o }, - .{ gdk.KEY_p, .p }, - .{ gdk.KEY_q, .q }, - .{ gdk.KEY_r, .r }, - .{ gdk.KEY_s, .s }, - .{ gdk.KEY_t, .t }, - .{ gdk.KEY_u, .u }, - .{ gdk.KEY_v, .v }, - .{ gdk.KEY_w, .w }, - .{ gdk.KEY_x, .x }, - .{ gdk.KEY_y, .y }, - .{ gdk.KEY_z, .z }, + .{ gdk.KEY_a, .key_a }, + .{ gdk.KEY_b, .key_b }, + .{ gdk.KEY_c, .key_c }, + .{ gdk.KEY_d, .key_d }, + .{ gdk.KEY_e, .key_e }, + .{ gdk.KEY_f, .key_f }, + .{ gdk.KEY_g, .key_g }, + .{ gdk.KEY_h, .key_h }, + .{ gdk.KEY_i, .key_i }, + .{ gdk.KEY_j, .key_j }, + .{ gdk.KEY_k, .key_k }, + .{ gdk.KEY_l, .key_l }, + .{ gdk.KEY_m, .key_m }, + .{ gdk.KEY_n, .key_n }, + .{ gdk.KEY_o, .key_o }, + .{ gdk.KEY_p, .key_p }, + .{ gdk.KEY_q, .key_q }, + .{ gdk.KEY_r, .key_r }, + .{ gdk.KEY_s, .key_s }, + .{ gdk.KEY_t, .key_t }, + .{ gdk.KEY_u, .key_u }, + .{ gdk.KEY_v, .key_v }, + .{ gdk.KEY_w, .key_w }, + .{ gdk.KEY_x, .key_x }, + .{ gdk.KEY_y, .key_y }, + .{ gdk.KEY_z, .key_z }, - .{ gdk.KEY_0, .zero }, - .{ gdk.KEY_1, .one }, - .{ gdk.KEY_2, .two }, - .{ gdk.KEY_3, .three }, - .{ gdk.KEY_4, .four }, - .{ gdk.KEY_5, .five }, - .{ gdk.KEY_6, .six }, - .{ gdk.KEY_7, .seven }, - .{ gdk.KEY_8, .eight }, - .{ gdk.KEY_9, .nine }, + .{ gdk.KEY_0, .digit_0 }, + .{ gdk.KEY_1, .digit_1 }, + .{ gdk.KEY_2, .digit_2 }, + .{ gdk.KEY_3, .digit_3 }, + .{ gdk.KEY_4, .digit_4 }, + .{ gdk.KEY_5, .digit_5 }, + .{ gdk.KEY_6, .digit_6 }, + .{ gdk.KEY_7, .digit_7 }, + .{ gdk.KEY_8, .digit_8 }, + .{ gdk.KEY_9, .digit_9 }, .{ gdk.KEY_semicolon, .semicolon }, .{ gdk.KEY_space, .space }, - .{ gdk.KEY_apostrophe, .apostrophe }, + .{ gdk.KEY_apostrophe, .quote }, .{ gdk.KEY_comma, .comma }, - .{ gdk.KEY_grave, .grave_accent }, + .{ gdk.KEY_grave, .backquote }, .{ gdk.KEY_period, .period }, .{ gdk.KEY_slash, .slash }, .{ gdk.KEY_minus, .minus }, .{ gdk.KEY_equal, .equal }, - .{ gdk.KEY_bracketleft, .left_bracket }, - .{ gdk.KEY_bracketright, .right_bracket }, + .{ gdk.KEY_bracketleft, .bracket_left }, + .{ gdk.KEY_bracketright, .bracket_right }, .{ gdk.KEY_backslash, .backslash }, - .{ gdk.KEY_Up, .up }, - .{ gdk.KEY_Down, .down }, - .{ gdk.KEY_Right, .right }, - .{ gdk.KEY_Left, .left }, + .{ gdk.KEY_Up, .arrow_up }, + .{ gdk.KEY_Down, .arrow_down }, + .{ gdk.KEY_Right, .arrow_right }, + .{ gdk.KEY_Left, .arrow_left }, .{ gdk.KEY_Home, .home }, .{ gdk.KEY_End, .end }, .{ gdk.KEY_Insert, .insert }, @@ -310,45 +310,45 @@ const keymap: []const RawEntry = &.{ .{ gdk.KEY_F24, .f24 }, .{ gdk.KEY_F25, .f25 }, - .{ gdk.KEY_KP_0, .kp_0 }, - .{ gdk.KEY_KP_1, .kp_1 }, - .{ gdk.KEY_KP_2, .kp_2 }, - .{ gdk.KEY_KP_3, .kp_3 }, - .{ gdk.KEY_KP_4, .kp_4 }, - .{ gdk.KEY_KP_5, .kp_5 }, - .{ gdk.KEY_KP_6, .kp_6 }, - .{ gdk.KEY_KP_7, .kp_7 }, - .{ gdk.KEY_KP_8, .kp_8 }, - .{ gdk.KEY_KP_9, .kp_9 }, - .{ gdk.KEY_KP_Decimal, .kp_decimal }, - .{ gdk.KEY_KP_Divide, .kp_divide }, - .{ gdk.KEY_KP_Multiply, .kp_multiply }, - .{ gdk.KEY_KP_Subtract, .kp_subtract }, - .{ gdk.KEY_KP_Add, .kp_add }, - .{ gdk.KEY_KP_Enter, .kp_enter }, - .{ gdk.KEY_KP_Equal, .kp_equal }, + .{ gdk.KEY_KP_0, .numpad_0 }, + .{ gdk.KEY_KP_1, .numpad_1 }, + .{ gdk.KEY_KP_2, .numpad_2 }, + .{ gdk.KEY_KP_3, .numpad_3 }, + .{ gdk.KEY_KP_4, .numpad_4 }, + .{ gdk.KEY_KP_5, .numpad_5 }, + .{ gdk.KEY_KP_6, .numpad_6 }, + .{ gdk.KEY_KP_7, .numpad_7 }, + .{ gdk.KEY_KP_8, .numpad_8 }, + .{ gdk.KEY_KP_9, .numpad_9 }, + .{ gdk.KEY_KP_Decimal, .numpad_decimal }, + .{ gdk.KEY_KP_Divide, .numpad_divide }, + .{ gdk.KEY_KP_Multiply, .numpad_multiply }, + .{ gdk.KEY_KP_Subtract, .numpad_subtract }, + .{ gdk.KEY_KP_Add, .numpad_add }, + .{ gdk.KEY_KP_Enter, .numpad_enter }, + .{ gdk.KEY_KP_Equal, .numpad_equal }, - .{ gdk.KEY_KP_Separator, .kp_separator }, - .{ gdk.KEY_KP_Left, .kp_left }, - .{ gdk.KEY_KP_Right, .kp_right }, - .{ gdk.KEY_KP_Up, .kp_up }, - .{ gdk.KEY_KP_Down, .kp_down }, - .{ gdk.KEY_KP_Page_Up, .kp_page_up }, - .{ gdk.KEY_KP_Page_Down, .kp_page_down }, - .{ gdk.KEY_KP_Home, .kp_home }, - .{ gdk.KEY_KP_End, .kp_end }, - .{ gdk.KEY_KP_Insert, .kp_insert }, - .{ gdk.KEY_KP_Delete, .kp_delete }, - .{ gdk.KEY_KP_Begin, .kp_begin }, + .{ gdk.KEY_KP_Separator, .numpad_separator }, + .{ gdk.KEY_KP_Left, .numpad_left }, + .{ gdk.KEY_KP_Right, .numpad_right }, + .{ gdk.KEY_KP_Up, .numpad_up }, + .{ gdk.KEY_KP_Down, .numpad_down }, + .{ gdk.KEY_KP_Page_Up, .numpad_page_up }, + .{ gdk.KEY_KP_Page_Down, .numpad_page_down }, + .{ gdk.KEY_KP_Home, .numpad_home }, + .{ gdk.KEY_KP_End, .numpad_end }, + .{ gdk.KEY_KP_Insert, .numpad_insert }, + .{ gdk.KEY_KP_Delete, .numpad_delete }, + .{ gdk.KEY_KP_Begin, .numpad_begin }, - .{ gdk.KEY_Shift_L, .left_shift }, - .{ gdk.KEY_Control_L, .left_control }, - .{ gdk.KEY_Alt_L, .left_alt }, - .{ gdk.KEY_Super_L, .left_super }, - .{ gdk.KEY_Shift_R, .right_shift }, - .{ gdk.KEY_Control_R, .right_control }, - .{ gdk.KEY_Alt_R, .right_alt }, - .{ gdk.KEY_Super_R, .right_super }, + .{ gdk.KEY_Shift_L, .shift_left }, + .{ gdk.KEY_Control_L, .control_left }, + .{ gdk.KEY_Alt_L, .alt_left }, + .{ gdk.KEY_Super_L, .meta_left }, + .{ gdk.KEY_Shift_R, .shift_right }, + .{ gdk.KEY_Control_R, .control_right }, + .{ gdk.KEY_Alt_R, .alt_right }, + .{ gdk.KEY_Super_R, .meta_right }, // TODO: media keys }; diff --git a/src/config/Config.zig b/src/config/Config.zig index 7d2814136..2a34f9c80 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -4495,17 +4495,17 @@ pub const Keybinds = struct { if (comptime !builtin.target.os.tag.isDarwin()) { try self.set.put( alloc, - .{ .key = .{ .physical = .n }, .mods = .{ .ctrl = true, .shift = true } }, + .{ .key = .{ .unicode = 'n' }, .mods = .{ .ctrl = true, .shift = true } }, .{ .new_window = {} }, ); try self.set.put( alloc, - .{ .key = .{ .physical = .w }, .mods = .{ .ctrl = true, .shift = true } }, + .{ .key = .{ .unicode = 'w' }, .mods = .{ .ctrl = true, .shift = true } }, .{ .close_surface = {} }, ); try self.set.put( alloc, - .{ .key = .{ .physical = .q }, .mods = .{ .ctrl = true, .shift = true } }, + .{ .key = .{ .unicode = 'q' }, .mods = .{ .ctrl = true, .shift = true } }, .{ .quit = {} }, ); try self.set.put( @@ -4515,22 +4515,22 @@ pub const Keybinds = struct { ); try self.set.put( alloc, - .{ .key = .{ .physical = .t }, .mods = .{ .ctrl = true, .shift = true } }, + .{ .key = .{ .unicode = 't' }, .mods = .{ .ctrl = true, .shift = true } }, .{ .new_tab = {} }, ); try self.set.put( alloc, - .{ .key = .{ .physical = .w }, .mods = .{ .ctrl = true, .shift = true } }, + .{ .key = .{ .unicode = 'w' }, .mods = .{ .ctrl = true, .shift = true } }, .{ .close_tab = {} }, ); try self.set.put( alloc, - .{ .key = .{ .physical = .left }, .mods = .{ .ctrl = true, .shift = true } }, + .{ .key = .{ .physical = .arrow_left }, .mods = .{ .ctrl = true, .shift = true } }, .{ .previous_tab = {} }, ); try self.set.put( alloc, - .{ .key = .{ .physical = .right }, .mods = .{ .ctrl = true, .shift = true } }, + .{ .key = .{ .physical = .arrow_right }, .mods = .{ .ctrl = true, .shift = true } }, .{ .next_tab = {} }, ); try self.set.put( @@ -4545,12 +4545,12 @@ pub const Keybinds = struct { ); try self.set.put( alloc, - .{ .key = .{ .physical = .o }, .mods = .{ .ctrl = true, .shift = true } }, + .{ .key = .{ .unicode = 'o' }, .mods = .{ .ctrl = true, .shift = true } }, .{ .new_split = .right }, ); try self.set.put( alloc, - .{ .key = .{ .physical = .e }, .mods = .{ .ctrl = true, .shift = true } }, + .{ .key = .{ .unicode = 'e' }, .mods = .{ .ctrl = true, .shift = true } }, .{ .new_split = .down }, ); try self.set.put( @@ -4565,51 +4565,46 @@ pub const Keybinds = struct { ); try self.set.put( alloc, - .{ .key = .{ .physical = .up }, .mods = .{ .ctrl = true, .alt = true } }, + .{ .key = .{ .physical = .arrow_up }, .mods = .{ .ctrl = true, .alt = true } }, .{ .goto_split = .up }, ); try self.set.put( alloc, - .{ .key = .{ .physical = .down }, .mods = .{ .ctrl = true, .alt = true } }, + .{ .key = .{ .physical = .arrow_down }, .mods = .{ .ctrl = true, .alt = true } }, .{ .goto_split = .down }, ); try self.set.put( alloc, - .{ .key = .{ .physical = .left }, .mods = .{ .ctrl = true, .alt = true } }, + .{ .key = .{ .physical = .arrow_left }, .mods = .{ .ctrl = true, .alt = true } }, .{ .goto_split = .left }, ); try self.set.put( alloc, - .{ .key = .{ .physical = .right }, .mods = .{ .ctrl = true, .alt = true } }, + .{ .key = .{ .physical = .arrow_right }, .mods = .{ .ctrl = true, .alt = true } }, .{ .goto_split = .right }, ); // Resizing splits try self.set.put( alloc, - .{ .key = .{ .physical = .up }, .mods = .{ .super = true, .ctrl = true, .shift = true } }, + .{ .key = .{ .physical = .arrow_up }, .mods = .{ .super = true, .ctrl = true, .shift = true } }, .{ .resize_split = .{ .up, 10 } }, ); try self.set.put( alloc, - .{ .key = .{ .physical = .down }, .mods = .{ .super = true, .ctrl = true, .shift = true } }, + .{ .key = .{ .physical = .arrow_down }, .mods = .{ .super = true, .ctrl = true, .shift = true } }, .{ .resize_split = .{ .down, 10 } }, ); try self.set.put( alloc, - .{ .key = .{ .physical = .left }, .mods = .{ .super = true, .ctrl = true, .shift = true } }, + .{ .key = .{ .physical = .arrow_left }, .mods = .{ .super = true, .ctrl = true, .shift = true } }, .{ .resize_split = .{ .left, 10 } }, ); try self.set.put( alloc, - .{ .key = .{ .physical = .right }, .mods = .{ .super = true, .ctrl = true, .shift = true } }, + .{ .key = .{ .physical = .arrow_right }, .mods = .{ .super = true, .ctrl = true, .shift = true } }, .{ .resize_split = .{ .right, 10 } }, ); - try self.set.put( - alloc, - .{ .key = .{ .physical = .plus }, .mods = .{ .super = true, .ctrl = true, .shift = true } }, - .{ .equalize_splits = {} }, - ); // Viewport scrolling try self.set.put( @@ -4648,14 +4643,14 @@ pub const Keybinds = struct { // Inspector, matching Chromium try self.set.put( alloc, - .{ .key = .{ .physical = .i }, .mods = .{ .shift = true, .ctrl = true } }, + .{ .key = .{ .unicode = 'i' }, .mods = .{ .shift = true, .ctrl = true } }, .{ .inspector = .toggle }, ); // Terminal try self.set.put( alloc, - .{ .key = .{ .physical = .a }, .mods = .{ .shift = true, .ctrl = true } }, + .{ .key = .{ .unicode = 'a' }, .mods = .{ .shift = true, .ctrl = true } }, .{ .select_all = {} }, ); diff --git a/src/input/key.zig b/src/input/key.zig index c0deea25c..7e770b332 100644 --- a/src/input/key.zig +++ b/src/input/key.zig @@ -398,6 +398,7 @@ pub const Key = enum(c_int) { // 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_separator, numpad_up, numpad_down, numpad_right, @@ -763,6 +764,7 @@ pub const Key = enum(c_int) { .convert, .kana_mode, .non_convert, + .numpad_separator, .numpad_backspace, .numpad_clear, .numpad_clear_entry,