From 57a527b0c9313e3ffc7aa8b4eaa33fb6ffa0e9d5 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 9 Aug 2023 19:42:13 -0700 Subject: [PATCH] macos: detect keyboard layout change and reload the keymap --- include/ghostty.h | 1 + macos/Sources/Ghostty/AppState.swift | 20 ++++++++++++++++++++ src/apprt/embedded.zig | 20 ++++++++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/include/ghostty.h b/include/ghostty.h index 658d3a456..798957b50 100644 --- a/include/ghostty.h +++ b/include/ghostty.h @@ -283,6 +283,7 @@ ghostty_app_t ghostty_app_new(const ghostty_runtime_config_s *, ghostty_config_t void ghostty_app_free(ghostty_app_t); bool ghostty_app_tick(ghostty_app_t); void *ghostty_app_userdata(ghostty_app_t); +void ghostty_app_keyboard_changed(ghostty_app_t); ghostty_surface_t ghostty_surface_new(ghostty_app_t, ghostty_surface_config_s*); void ghostty_surface_free(ghostty_surface_t); diff --git a/macos/Sources/Ghostty/AppState.swift b/macos/Sources/Ghostty/AppState.swift index 3bc180288..68076c224 100644 --- a/macos/Sources/Ghostty/AppState.swift +++ b/macos/Sources/Ghostty/AppState.swift @@ -74,6 +74,13 @@ extension Ghostty { return } self.app = app + + // Subscribe to notifications for keyboard layout change so that we can update Ghostty. + NotificationCenter.default.addObserver( + self, + selector: #selector(self.keyboardSelectionDidChange(notification:)), + name: NSTextInputContext.keyboardSelectionDidChangeNotification, + object: nil) self.readiness = .ready } @@ -82,6 +89,12 @@ extension Ghostty { // This will force the didSet callbacks to run which free. self.app = nil self.config = nil + + // Remove our observer + NotificationCenter.default.removeObserver( + self, + name: NSTextInputContext.keyboardSelectionDidChangeNotification, + object: nil) } /// Initializes a new configuration and loads all the values. @@ -132,6 +145,13 @@ extension Ghostty { ghostty_surface_split_focus(surface, direction.toNative()) } + // Called when the selected keyboard changes. We have to notify Ghostty so that + // it can reload the keyboard mapping for input. + @objc private func keyboardSelectionDidChange(notification: NSNotification) { + guard let app = self.app else { return } + ghostty_app_keyboard_changed(app) + } + // MARK: Ghostty Callbacks static func newSplit(_ userdata: UnsafeMutableRawPointer?, direction: ghostty_split_direction_e) { diff --git a/src/apprt/embedded.zig b/src/apprt/embedded.zig index 43bc7eb43..6d3dd7f43 100644 --- a/src/apprt/embedded.zig +++ b/src/apprt/embedded.zig @@ -92,6 +92,17 @@ pub const App = struct { self.keymap.deinit(); } + /// This should be called whenever the keyboard layout was changed. + pub fn reloadKeymap(self: *App) !void { + // Reload the keymap + try self.keymap.reload(); + + // Clear the dead key state since we changed the keymap, any + // dead key state is just forgotten. i.e. if you type ' on us-intl + // and then switch to us and type a, you'll get a rather than รก. + self.keymap_state = .{}; + } + pub fn reloadConfig(self: *App) !?*const Config { // Reload if (self.opts.reload_config(self.opts.userdata)) |new| { @@ -475,6 +486,15 @@ pub const CAPI = struct { core_app.destroy(); } + /// Notify the app that the keyboard was changed. This causes the + /// keyboard layout to be reloaded from the OS. + export fn ghostty_app_keyboard_changed(v: *App) void { + v.reloadKeymap() catch |err| { + log.err("error reloading keyboard map err={}", .{err}); + return; + }; + } + /// Create a new surface as part of an app. export fn ghostty_surface_new( app: *App,