mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
macos: begin syncing menuitem key equivalents
This commit is contained in:
@ -11,6 +11,7 @@
|
||||
85102A1C2A6E32890084AB3E /* PrimaryWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85102A1B2A6E32890084AB3E /* PrimaryWindowController.swift */; };
|
||||
857F63812A5E64F200CA4815 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 857F63802A5E64F200CA4815 /* MainMenu.xib */; };
|
||||
85DE1C922A6A3DCA00493853 /* PrimaryWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85DE1C912A6A3DCA00493853 /* PrimaryWindow.swift */; };
|
||||
A5278A9B2AA05B2600CD3039 /* Ghostty.Input.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5278A9A2AA05B2600CD3039 /* Ghostty.Input.swift */; };
|
||||
A53426352A7DA53D00EBB7A2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A53426342A7DA53D00EBB7A2 /* AppDelegate.swift */; };
|
||||
A53426392A7DC55C00EBB7A2 /* PrimaryWindowManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A53426382A7DC55C00EBB7A2 /* PrimaryWindowManager.swift */; };
|
||||
A535B9DA299C569B0017E2E4 /* ErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A535B9D9299C569B0017E2E4 /* ErrorView.swift */; };
|
||||
@ -37,6 +38,7 @@
|
||||
85102A1B2A6E32890084AB3E /* PrimaryWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrimaryWindowController.swift; sourceTree = "<group>"; };
|
||||
857F63802A5E64F200CA4815 /* MainMenu.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainMenu.xib; sourceTree = "<group>"; };
|
||||
85DE1C912A6A3DCA00493853 /* PrimaryWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrimaryWindow.swift; sourceTree = "<group>"; };
|
||||
A5278A9A2AA05B2600CD3039 /* Ghostty.Input.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Ghostty.Input.swift; sourceTree = "<group>"; };
|
||||
A53426342A7DA53D00EBB7A2 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
A53426382A7DC55C00EBB7A2 /* PrimaryWindowManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrimaryWindowManager.swift; sourceTree = "<group>"; };
|
||||
A535B9D9299C569B0017E2E4 /* ErrorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorView.swift; sourceTree = "<group>"; };
|
||||
@ -132,6 +134,7 @@
|
||||
A55B7BB729B6F53A0055DE60 /* Package.swift */,
|
||||
A55B7BB529B6F47F0055DE60 /* AppState.swift */,
|
||||
A55B7BBB29B6FC330055DE60 /* SurfaceView.swift */,
|
||||
A5278A9A2AA05B2600CD3039 /* Ghostty.Input.swift */,
|
||||
A55B7BBD29B701360055DE60 /* Ghostty.SplitView.swift */,
|
||||
A55685DF29A03A9F004303CE /* AppError.swift */,
|
||||
);
|
||||
@ -260,6 +263,7 @@
|
||||
files = (
|
||||
A53426392A7DC55C00EBB7A2 /* PrimaryWindowManager.swift in Sources */,
|
||||
85DE1C922A6A3DCA00493853 /* PrimaryWindow.swift in Sources */,
|
||||
A5278A9B2AA05B2600CD3039 /* Ghostty.Input.swift in Sources */,
|
||||
A53426352A7DA53D00EBB7A2 /* AppDelegate.swift in Sources */,
|
||||
A55B7BBC29B6FC330055DE60 /* SurfaceView.swift in Sources */,
|
||||
A59444F729A2ED5200725BBA /* SettingsView.swift in Sources */,
|
||||
|
@ -14,6 +14,10 @@ class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
|
||||
// confirmQuit published so other views can check whether quit needs to be confirmed.
|
||||
@Published var confirmQuit: Bool = false
|
||||
|
||||
/// Various menu items so that we can programmatically sync the keyboard shortcut with the Ghostty config.
|
||||
@IBOutlet private var menuPreviousSplit: NSMenuItem?
|
||||
@IBOutlet private var menuNextSplit: NSMenuItem?
|
||||
|
||||
/// The ghostty global state. Only one per process.
|
||||
private var ghostty: Ghostty.AppState = Ghostty.AppState()
|
||||
|
||||
@ -33,6 +37,9 @@ class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
|
||||
"ApplePressAndHoldEnabled": false,
|
||||
])
|
||||
|
||||
// Sync our menu shortcuts with our Ghostty config
|
||||
syncMenuShortcuts()
|
||||
|
||||
// Let's launch our first window.
|
||||
// TODO: we should detect if we restored windows and if so not launch a new window.
|
||||
windowManager.addInitialWindow()
|
||||
@ -76,6 +83,29 @@ class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
|
||||
return .terminateLater
|
||||
}
|
||||
|
||||
private func syncMenuShortcuts() {
|
||||
guard let cfg = ghostty.config else { return }
|
||||
|
||||
if let menu = self.menuPreviousSplit {
|
||||
let action = "goto_split:previous"
|
||||
let trigger = ghostty_config_trigger(cfg, action, UInt(action.count))
|
||||
if let equiv = Ghostty.keyEquivalent(key: trigger.key) {
|
||||
menu.keyEquivalent = equiv
|
||||
menu.keyEquivalentModifierMask = Ghostty.eventModifierFlags(mods: trigger.mods)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func focusedSurface() -> ghostty_surface_t? {
|
||||
guard let window = NSApp.keyWindow as? PrimaryWindow else { return nil }
|
||||
return window.focusedSurfaceWrapper.surface
|
||||
}
|
||||
|
||||
private func splitMoveFocus(direction: Ghostty.SplitFocusDirection) {
|
||||
guard let surface = focusedSurface() else { return }
|
||||
ghostty.splitMoveFocus(surface: surface, direction: direction)
|
||||
}
|
||||
|
||||
@IBAction func newWindow(_ sender: Any?) {
|
||||
windowManager.newWindow()
|
||||
}
|
||||
@ -98,11 +128,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
|
||||
ghostty.requestClose(surface: surface)
|
||||
}
|
||||
|
||||
private func focusedSurface() -> ghostty_surface_t? {
|
||||
guard let window = NSApp.keyWindow as? PrimaryWindow else { return nil }
|
||||
return window.focusedSurfaceWrapper.surface
|
||||
}
|
||||
|
||||
@IBAction func splitHorizontally(_ sender: Any) {
|
||||
guard let surface = focusedSurface() else { return }
|
||||
ghostty.split(surface: surface, direction: GHOSTTY_SPLIT_RIGHT)
|
||||
@ -137,11 +162,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
|
||||
splitMoveFocus(direction: .right)
|
||||
}
|
||||
|
||||
func splitMoveFocus(direction: Ghostty.SplitFocusDirection) {
|
||||
guard let surface = focusedSurface() else { return }
|
||||
ghostty.splitMoveFocus(surface: surface, direction: direction)
|
||||
}
|
||||
|
||||
@IBAction func showHelp(_ sender: Any) {
|
||||
guard let url = URL(string: "https://github.com/mitchellh/ghostty") else { return }
|
||||
NSWorkspace.shared.open(url)
|
||||
|
158
macos/Sources/Ghostty/Ghostty.Input.swift
Normal file
158
macos/Sources/Ghostty/Ghostty.Input.swift
Normal file
@ -0,0 +1,158 @@
|
||||
import Cocoa
|
||||
import GhosttyKit
|
||||
|
||||
extension Ghostty {
|
||||
/// Returns the "keyEquivalent" string for a given input key. This doesn't always have a corresponding key.
|
||||
static func keyEquivalent(key: ghostty_input_key_e) -> String? {
|
||||
guard let byte = Self.keyToAscii[key] else { return nil }
|
||||
return String(bytes: [byte], encoding: .utf8)
|
||||
}
|
||||
|
||||
/// Returns the event modifier flags set for the Ghostty mods enum.
|
||||
static func eventModifierFlags(mods: ghostty_input_mods_e) -> NSEvent.ModifierFlags {
|
||||
var flags: [NSEvent.ModifierFlags] = [];
|
||||
if (mods.rawValue & GHOSTTY_MODS_SHIFT.rawValue != 0) { flags.append(.shift) }
|
||||
if (mods.rawValue & GHOSTTY_MODS_CTRL.rawValue != 0) { flags.append(.control) }
|
||||
if (mods.rawValue & GHOSTTY_MODS_ALT.rawValue != 0) { flags.append(.option) }
|
||||
if (mods.rawValue & GHOSTTY_MODS_SUPER.rawValue != 0) { flags.append(.command) }
|
||||
return NSEvent.ModifierFlags(flags)
|
||||
}
|
||||
|
||||
static let keyToAscii: [ghostty_input_key_e : UInt8] = [
|
||||
// 0-9
|
||||
GHOSTTY_KEY_ZERO: 0x30,
|
||||
GHOSTTY_KEY_ONE: 0x31,
|
||||
GHOSTTY_KEY_TWO: 0x32,
|
||||
GHOSTTY_KEY_THREE: 0x33,
|
||||
GHOSTTY_KEY_FOUR: 0x34,
|
||||
GHOSTTY_KEY_FIVE: 0x35,
|
||||
GHOSTTY_KEY_SIX: 0x36,
|
||||
GHOSTTY_KEY_SEVEN: 0x37,
|
||||
GHOSTTY_KEY_EIGHT: 0x38,
|
||||
GHOSTTY_KEY_NINE: 0x39,
|
||||
|
||||
// a-z
|
||||
GHOSTTY_KEY_A: 0x61,
|
||||
GHOSTTY_KEY_B: 0x62,
|
||||
GHOSTTY_KEY_C: 0x63,
|
||||
GHOSTTY_KEY_D: 0x64,
|
||||
GHOSTTY_KEY_E: 0x65,
|
||||
GHOSTTY_KEY_F: 0x66,
|
||||
GHOSTTY_KEY_G: 0x67,
|
||||
GHOSTTY_KEY_H: 0x68,
|
||||
GHOSTTY_KEY_I: 0x69,
|
||||
GHOSTTY_KEY_J: 0x6A,
|
||||
GHOSTTY_KEY_K: 0x6B,
|
||||
GHOSTTY_KEY_L: 0x6C,
|
||||
GHOSTTY_KEY_M: 0x6D,
|
||||
GHOSTTY_KEY_N: 0x6E,
|
||||
GHOSTTY_KEY_O: 0x6F,
|
||||
GHOSTTY_KEY_P: 0x70,
|
||||
GHOSTTY_KEY_Q: 0x71,
|
||||
GHOSTTY_KEY_R: 0x72,
|
||||
GHOSTTY_KEY_S: 0x73,
|
||||
GHOSTTY_KEY_T: 0x74,
|
||||
GHOSTTY_KEY_U: 0x75,
|
||||
GHOSTTY_KEY_V: 0x76,
|
||||
GHOSTTY_KEY_W: 0x77,
|
||||
GHOSTTY_KEY_X: 0x78,
|
||||
GHOSTTY_KEY_Y: 0x79,
|
||||
GHOSTTY_KEY_Z: 0x7A,
|
||||
|
||||
// Symbols
|
||||
GHOSTTY_KEY_APOSTROPHE: 0x27,
|
||||
GHOSTTY_KEY_BACKSLASH: 0x5C,
|
||||
GHOSTTY_KEY_COMMA: 0x2C,
|
||||
GHOSTTY_KEY_EQUAL: 0x3D,
|
||||
GHOSTTY_KEY_GRAVE_ACCENT: 0x60,
|
||||
GHOSTTY_KEY_LEFT_BRACKET: 0x5B,
|
||||
GHOSTTY_KEY_MINUS: 0x2D,
|
||||
GHOSTTY_KEY_PERIOD: 0x2E,
|
||||
GHOSTTY_KEY_RIGHT_BRACKET: 0x5D,
|
||||
GHOSTTY_KEY_SEMICOLON: 0x3B,
|
||||
GHOSTTY_KEY_SLASH: 0x2F,
|
||||
]
|
||||
|
||||
static let asciiToKey: [UInt8 : ghostty_input_key_e] = [
|
||||
// 0-9
|
||||
0x30: GHOSTTY_KEY_ZERO,
|
||||
0x31: GHOSTTY_KEY_ONE,
|
||||
0x32: GHOSTTY_KEY_TWO,
|
||||
0x33: GHOSTTY_KEY_THREE,
|
||||
0x34: GHOSTTY_KEY_FOUR,
|
||||
0x35: GHOSTTY_KEY_FIVE,
|
||||
0x36: GHOSTTY_KEY_SIX,
|
||||
0x37: GHOSTTY_KEY_SEVEN,
|
||||
0x38: GHOSTTY_KEY_EIGHT,
|
||||
0x39: GHOSTTY_KEY_NINE,
|
||||
|
||||
// A-Z
|
||||
0x41: GHOSTTY_KEY_A,
|
||||
0x42: GHOSTTY_KEY_B,
|
||||
0x43: GHOSTTY_KEY_C,
|
||||
0x44: GHOSTTY_KEY_D,
|
||||
0x45: GHOSTTY_KEY_E,
|
||||
0x46: GHOSTTY_KEY_F,
|
||||
0x47: GHOSTTY_KEY_G,
|
||||
0x48: GHOSTTY_KEY_H,
|
||||
0x49: GHOSTTY_KEY_I,
|
||||
0x4A: GHOSTTY_KEY_J,
|
||||
0x4B: GHOSTTY_KEY_K,
|
||||
0x4C: GHOSTTY_KEY_L,
|
||||
0x4D: GHOSTTY_KEY_M,
|
||||
0x4E: GHOSTTY_KEY_N,
|
||||
0x4F: GHOSTTY_KEY_O,
|
||||
0x50: GHOSTTY_KEY_P,
|
||||
0x51: GHOSTTY_KEY_Q,
|
||||
0x52: GHOSTTY_KEY_R,
|
||||
0x53: GHOSTTY_KEY_S,
|
||||
0x54: GHOSTTY_KEY_T,
|
||||
0x55: GHOSTTY_KEY_U,
|
||||
0x56: GHOSTTY_KEY_V,
|
||||
0x57: GHOSTTY_KEY_W,
|
||||
0x58: GHOSTTY_KEY_X,
|
||||
0x59: GHOSTTY_KEY_Y,
|
||||
0x5A: GHOSTTY_KEY_Z,
|
||||
|
||||
// a-z
|
||||
0x61: GHOSTTY_KEY_A,
|
||||
0x62: GHOSTTY_KEY_B,
|
||||
0x63: GHOSTTY_KEY_C,
|
||||
0x64: GHOSTTY_KEY_D,
|
||||
0x65: GHOSTTY_KEY_E,
|
||||
0x66: GHOSTTY_KEY_F,
|
||||
0x67: GHOSTTY_KEY_G,
|
||||
0x68: GHOSTTY_KEY_H,
|
||||
0x69: GHOSTTY_KEY_I,
|
||||
0x6A: GHOSTTY_KEY_J,
|
||||
0x6B: GHOSTTY_KEY_K,
|
||||
0x6C: GHOSTTY_KEY_L,
|
||||
0x6D: GHOSTTY_KEY_M,
|
||||
0x6E: GHOSTTY_KEY_N,
|
||||
0x6F: GHOSTTY_KEY_O,
|
||||
0x70: GHOSTTY_KEY_P,
|
||||
0x71: GHOSTTY_KEY_Q,
|
||||
0x72: GHOSTTY_KEY_R,
|
||||
0x73: GHOSTTY_KEY_S,
|
||||
0x74: GHOSTTY_KEY_T,
|
||||
0x75: GHOSTTY_KEY_U,
|
||||
0x76: GHOSTTY_KEY_V,
|
||||
0x77: GHOSTTY_KEY_W,
|
||||
0x78: GHOSTTY_KEY_X,
|
||||
0x79: GHOSTTY_KEY_Y,
|
||||
0x7A: GHOSTTY_KEY_Z,
|
||||
|
||||
// Symbols
|
||||
0x27: GHOSTTY_KEY_APOSTROPHE,
|
||||
0x5C: GHOSTTY_KEY_BACKSLASH,
|
||||
0x2C: GHOSTTY_KEY_COMMA,
|
||||
0x3D: GHOSTTY_KEY_EQUAL,
|
||||
0x60: GHOSTTY_KEY_GRAVE_ACCENT,
|
||||
0x5B: GHOSTTY_KEY_LEFT_BRACKET,
|
||||
0x2D: GHOSTTY_KEY_MINUS,
|
||||
0x2E: GHOSTTY_KEY_PERIOD,
|
||||
0x5D: GHOSTTY_KEY_RIGHT_BRACKET,
|
||||
0x3B: GHOSTTY_KEY_SEMICOLON,
|
||||
0x2F: GHOSTTY_KEY_SLASH,
|
||||
]
|
||||
}
|
@ -624,89 +624,6 @@ extension Ghostty {
|
||||
0x43: GHOSTTY_KEY_KP_MULTIPLY,
|
||||
0x4E: GHOSTTY_KEY_KP_SUBTRACT,
|
||||
];
|
||||
|
||||
static let ascii: [UInt8 : ghostty_input_key_e] = [
|
||||
// 0-9
|
||||
0x30: GHOSTTY_KEY_ZERO,
|
||||
0x31: GHOSTTY_KEY_ONE,
|
||||
0x32: GHOSTTY_KEY_TWO,
|
||||
0x33: GHOSTTY_KEY_THREE,
|
||||
0x34: GHOSTTY_KEY_FOUR,
|
||||
0x35: GHOSTTY_KEY_FIVE,
|
||||
0x36: GHOSTTY_KEY_SIX,
|
||||
0x37: GHOSTTY_KEY_SEVEN,
|
||||
0x38: GHOSTTY_KEY_EIGHT,
|
||||
0x39: GHOSTTY_KEY_NINE,
|
||||
|
||||
// A-Z
|
||||
0x41: GHOSTTY_KEY_A,
|
||||
0x42: GHOSTTY_KEY_B,
|
||||
0x43: GHOSTTY_KEY_C,
|
||||
0x44: GHOSTTY_KEY_D,
|
||||
0x45: GHOSTTY_KEY_E,
|
||||
0x46: GHOSTTY_KEY_F,
|
||||
0x47: GHOSTTY_KEY_G,
|
||||
0x48: GHOSTTY_KEY_H,
|
||||
0x49: GHOSTTY_KEY_I,
|
||||
0x4A: GHOSTTY_KEY_J,
|
||||
0x4B: GHOSTTY_KEY_K,
|
||||
0x4C: GHOSTTY_KEY_L,
|
||||
0x4D: GHOSTTY_KEY_M,
|
||||
0x4E: GHOSTTY_KEY_N,
|
||||
0x4F: GHOSTTY_KEY_O,
|
||||
0x50: GHOSTTY_KEY_P,
|
||||
0x51: GHOSTTY_KEY_Q,
|
||||
0x52: GHOSTTY_KEY_R,
|
||||
0x53: GHOSTTY_KEY_S,
|
||||
0x54: GHOSTTY_KEY_T,
|
||||
0x55: GHOSTTY_KEY_U,
|
||||
0x56: GHOSTTY_KEY_V,
|
||||
0x57: GHOSTTY_KEY_W,
|
||||
0x58: GHOSTTY_KEY_X,
|
||||
0x59: GHOSTTY_KEY_Y,
|
||||
0x5A: GHOSTTY_KEY_Z,
|
||||
|
||||
// a-z
|
||||
0x61: GHOSTTY_KEY_A,
|
||||
0x62: GHOSTTY_KEY_B,
|
||||
0x63: GHOSTTY_KEY_C,
|
||||
0x64: GHOSTTY_KEY_D,
|
||||
0x65: GHOSTTY_KEY_E,
|
||||
0x66: GHOSTTY_KEY_F,
|
||||
0x67: GHOSTTY_KEY_G,
|
||||
0x68: GHOSTTY_KEY_H,
|
||||
0x69: GHOSTTY_KEY_I,
|
||||
0x6A: GHOSTTY_KEY_J,
|
||||
0x6B: GHOSTTY_KEY_K,
|
||||
0x6C: GHOSTTY_KEY_L,
|
||||
0x6D: GHOSTTY_KEY_M,
|
||||
0x6E: GHOSTTY_KEY_N,
|
||||
0x6F: GHOSTTY_KEY_O,
|
||||
0x70: GHOSTTY_KEY_P,
|
||||
0x71: GHOSTTY_KEY_Q,
|
||||
0x72: GHOSTTY_KEY_R,
|
||||
0x73: GHOSTTY_KEY_S,
|
||||
0x74: GHOSTTY_KEY_T,
|
||||
0x75: GHOSTTY_KEY_U,
|
||||
0x76: GHOSTTY_KEY_V,
|
||||
0x77: GHOSTTY_KEY_W,
|
||||
0x78: GHOSTTY_KEY_X,
|
||||
0x79: GHOSTTY_KEY_Y,
|
||||
0x7A: GHOSTTY_KEY_Z,
|
||||
|
||||
// Symbols
|
||||
0x27: GHOSTTY_KEY_APOSTROPHE,
|
||||
0x5C: GHOSTTY_KEY_BACKSLASH,
|
||||
0x2C: GHOSTTY_KEY_COMMA,
|
||||
0x3D: GHOSTTY_KEY_EQUAL,
|
||||
0x60: GHOSTTY_KEY_GRAVE_ACCENT,
|
||||
0x5B: GHOSTTY_KEY_LEFT_BRACKET,
|
||||
0x2D: GHOSTTY_KEY_MINUS,
|
||||
0x2E: GHOSTTY_KEY_PERIOD,
|
||||
0x5D: GHOSTTY_KEY_RIGHT_BRACKET,
|
||||
0x3B: GHOSTTY_KEY_SEMICOLON,
|
||||
0x2F: GHOSTTY_KEY_SLASH,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,12 @@
|
||||
</customObject>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<customObject id="bbz-4X-AYv" userLabel="AppDelegate" customClass="AppDelegate" customModule="Ghostty" customModuleProvider="target"/>
|
||||
<customObject id="bbz-4X-AYv" userLabel="AppDelegate" customClass="AppDelegate" customModule="Ghostty" customModuleProvider="target">
|
||||
<connections>
|
||||
<outlet property="menuNextSplit" destination="bD7-ei-wKU" id="LeT-xw-eh4"/>
|
||||
<outlet property="menuPreviousSplit" destination="Lic-px-1wg" id="Rto-CG-yRe"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
|
||||
<menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
|
||||
<items>
|
||||
|
Reference in New Issue
Block a user