From 573b163636d5c76ff2592d07bfdff434d2671dd0 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 17 Feb 2023 22:12:03 -0800 Subject: [PATCH] start input, its broken but we're getting there --- include/ghostty.h | 150 ++++++++++++++++++++++++ macos/Sources/TerminalSurfaceView.swift | 7 ++ src/App.zig | 11 ++ src/apprt/embedded.zig | 13 ++ src/input/key.zig | 21 +++- src/termio/Exec.zig | 2 +- 6 files changed, 199 insertions(+), 5 deletions(-) diff --git a/include/ghostty.h b/include/ghostty.h index 5bf1fd588..c7d65e4b0 100644 --- a/include/ghostty.h +++ b/include/ghostty.h @@ -14,8 +14,19 @@ extern "C" { #include +//------------------------------------------------------------------- +// Macros + #define GHOSTTY_SUCCESS 0 +// Masks for input modifiers +#define GHOSTTY_INPUT_SHIFT 1 +#define GHOSTTY_INPUT_CTRL 2 +#define GHOSTTY_INPUT_ALT 4 +#define GHOSTTY_INPUT_SUPER 8 +#define GHOSTTY_INPUT_CAPS 16 +#define GHOSTTY_INPUT_NUM 32 + //------------------------------------------------------------------- // Types @@ -23,15 +34,153 @@ extern "C" { // structs. To find the Zig struct, grep for this type name. The documentation // for all of these types is available in the Zig source. typedef void (*ghostty_runtime_wakeup_cb)(void *); + typedef struct { void *userdata; ghostty_runtime_wakeup_cb wakeup_cb; } ghostty_runtime_config_s; + typedef struct { void *nsview; double scale_factor; } ghostty_surface_config_s; +typedef enum { release, press, repeat } ghostty_input_action_e; +typedef enum { + invalid, + + // a-z + a, + b, + c, + d, + e, + f, + g, + h, + i, + j, + k, + l, + m, + n, + o, + p, + q, + r, + s, + t, + u, + v, + w, + x, + y, + z, + + // numbers + zero, + one, + two, + three, + four, + five, + six, + seven, + eight, + nine, + + // puncuation + semicolon, + space, + apostrophe, + comma, + grave_accent, // ` + period, + slash, + minus, + equal, + left_bracket, // [ + right_bracket, // ] + backslash, // / + + // control + up, + down, + right, + left, + home, + end, + insert, + delete, + caps_lock, + scroll_lock, + num_lock, + page_up, + page_down, + escape, + enter, + tab, + backspace, + print_screen, + pause, + + // function keys + f1, + f2, + f3, + f4, + f5, + f6, + f7, + f8, + f9, + f10, + f11, + f12, + f13, + f14, + f15, + f16, + f17, + f18, + f19, + f20, + f21, + f22, + f23, + f24, + f25, + + // keypad + kp_0, + kp_1, + kp_2, + kp_3, + kp_4, + kp_5, + kp_6, + kp_7, + kp_8, + kp_9, + kp_decimal, + kp_divide, + kp_multiply, + kp_subtract, + kp_add, + kp_enter, + kp_equal, + + // modifiers + left_shift, + left_control, + left_alt, + left_super, + right_shift, + right_control, + right_alt, + right_super, +} ghostty_input_key_e; + // Opaque types typedef void *ghostty_app_t; typedef void *ghostty_config_t; @@ -56,6 +205,7 @@ void ghostty_surface_free(ghostty_surface_t); void ghostty_surface_refresh(ghostty_surface_t); void ghostty_surface_set_content_scale(ghostty_surface_t, double, double); void ghostty_surface_set_size(ghostty_surface_t, uint32_t, uint32_t); +void ghostty_surface_key(ghostty_surface_t, ghostty_input_action_e, ghostty_input_key_e, uint8_t); #ifdef __cplusplus } diff --git a/macos/Sources/TerminalSurfaceView.swift b/macos/Sources/TerminalSurfaceView.swift index 822c2beff..f8c51a860 100644 --- a/macos/Sources/TerminalSurfaceView.swift +++ b/macos/Sources/TerminalSurfaceView.swift @@ -96,6 +96,13 @@ class TerminalSurfaceView_Real: NSView, ObservableObject { override func keyDown(with event: NSEvent) { print("Key down: \(event)") + + if let surface = self.surface { + if (event.keyCode == 36) { + ghostty_surface_key(surface, press, enter, 0) + } + } + self.interpretKeyEvents([event]) } diff --git a/src/App.zig b/src/App.zig index 71793666c..e28f3b76e 100644 --- a/src/App.zig +++ b/src/App.zig @@ -11,6 +11,7 @@ const build_config = @import("build_config.zig"); const apprt = @import("apprt.zig"); const Window = @import("Window.zig"); const tracy = @import("tracy"); +const input = @import("input.zig"); const Config = @import("config.zig").Config; const BlockingQueue = @import("./blocking_queue.zig").BlockingQueue; const renderer = @import("renderer.zig"); @@ -412,4 +413,14 @@ pub const CAPI = struct { export fn ghostty_surface_set_content_scale(win: *Window, x: f64, y: f64) void { win.window.updateContentScale(x, y); } + + /// Tell the surface that it needs to schedule a render + export fn ghostty_surface_key( + win: *Window, + action: input.Action, + key: input.Key, + mods: input.Mods, + ) void { + win.window.keyCallback(action, key, mods); + } }; diff --git a/src/apprt/embedded.zig b/src/apprt/embedded.zig index d53b4a80d..0cb101b0e 100644 --- a/src/apprt/embedded.zig +++ b/src/apprt/embedded.zig @@ -10,6 +10,7 @@ const assert = std.debug.assert; const Allocator = std.mem.Allocator; const objc = @import("objc"); const apprt = @import("../apprt.zig"); +const input = @import("../input.zig"); const CoreApp = @import("../App.zig"); const CoreWindow = @import("../Window.zig"); @@ -143,4 +144,16 @@ pub const Window = struct { return; }; } + + pub fn keyCallback( + self: *const Window, + action: input.Action, + key: input.Key, + mods: input.Mods, + ) void { + self.core_win.keyCallback(action, key, mods) catch |err| { + log.err("error in key callback err={}", .{err}); + return; + }; + } }; diff --git a/src/input/key.zig b/src/input/key.zig index 78b5175da..6892fc72a 100644 --- a/src/input/key.zig +++ b/src/input/key.zig @@ -3,7 +3,7 @@ const Allocator = std.mem.Allocator; /// A bitmask for all key modifiers. This is taken directly from the /// GLFW representation, but we use this generically. -pub const Mods = packed struct { +pub const Mods = packed struct(u8) { shift: bool = false, ctrl: bool = false, alt: bool = false, @@ -11,10 +11,21 @@ pub const Mods = packed struct { caps_lock: bool = false, num_lock: bool = false, _padding: u2 = 0, + + // For our own understanding + test { + const testing = std.testing; + try testing.expectEqual(@bitCast(u8, Mods{}), @as(u8, 0b0)); + try testing.expectEqual( + @bitCast(u8, Mods{ .shift = true }), + @as(u8, 0b0000_0001), + ); + } }; -/// The action associated with an input event. -pub const Action = enum { +/// The action associated with an input event. This is backed by a c_int +/// so that we can use the enum as-is for our embedding API. +pub const Action = enum(c_int) { release, press, repeat, @@ -25,7 +36,9 @@ pub const Action = enum { /// this only needs to accomodate what maps to a key. If a key is not bound /// to anything and the key can be mapped to a printable character, then that /// unicode character is sent directly to the pty. -pub const Key = enum { +/// +/// This is backed by a c_int so we can use this as-is for our embedding API. +pub const Key = enum(c_int) { invalid, // a-z diff --git a/src/termio/Exec.zig b/src/termio/Exec.zig index c6e382750..d4fc39abb 100644 --- a/src/termio/Exec.zig +++ b/src/termio/Exec.zig @@ -529,7 +529,7 @@ const ReadThread = struct { return; }; - // log.info("DATA: {d}", .{n}); + log.info("DATA: {d}", .{n}); @call(.always_inline, process, .{ ev, buf[0..n] }); } }