Make the function/globe key available as a modifier on macOS

This commit is contained in:
Mitchell Hashimoto
2024-10-05 06:46:34 -10:00
parent a36bdd97de
commit 6fdfa9d491
7 changed files with 36 additions and 12 deletions

View File

@ -88,12 +88,13 @@ typedef enum {
GHOSTTY_MODS_CTRL = 1 << 1, GHOSTTY_MODS_CTRL = 1 << 1,
GHOSTTY_MODS_ALT = 1 << 2, GHOSTTY_MODS_ALT = 1 << 2,
GHOSTTY_MODS_SUPER = 1 << 3, GHOSTTY_MODS_SUPER = 1 << 3,
GHOSTTY_MODS_CAPS = 1 << 4, GHOSTTY_MODS_FN = 1 << 4,
GHOSTTY_MODS_NUM = 1 << 5, GHOSTTY_MODS_CAPS = 1 << 5,
GHOSTTY_MODS_SHIFT_RIGHT = 1 << 6, GHOSTTY_MODS_NUM = 1 << 6,
GHOSTTY_MODS_CTRL_RIGHT = 1 << 7, GHOSTTY_MODS_SHIFT_RIGHT = 1 << 7,
GHOSTTY_MODS_ALT_RIGHT = 1 << 8, GHOSTTY_MODS_CTRL_RIGHT = 1 << 8,
GHOSTTY_MODS_SUPER_RIGHT = 1 << 9, GHOSTTY_MODS_ALT_RIGHT = 1 << 9,
GHOSTTY_MODS_SUPER_RIGHT = 1 << 10,
} ghostty_input_mods_e; } ghostty_input_mods_e;
typedef enum { typedef enum {

View File

@ -348,6 +348,11 @@ class AppDelegate: NSObject,
return return
} }
if (equiv.modifiers.contains(.function)) {
// NSMenuItem key equivalent cannot contain function modifiers.
return
}
menu.keyEquivalent = equiv.key menu.keyEquivalent = equiv.key
menu.keyEquivalentModifierMask = equiv.modifiers menu.keyEquivalentModifierMask = equiv.modifiers
} }

View File

@ -14,6 +14,7 @@ extension Ghostty {
if (mods.rawValue & GHOSTTY_MODS_CTRL.rawValue != 0) { flags.insert(.control) } if (mods.rawValue & GHOSTTY_MODS_CTRL.rawValue != 0) { flags.insert(.control) }
if (mods.rawValue & GHOSTTY_MODS_ALT.rawValue != 0) { flags.insert(.option) } if (mods.rawValue & GHOSTTY_MODS_ALT.rawValue != 0) { flags.insert(.option) }
if (mods.rawValue & GHOSTTY_MODS_SUPER.rawValue != 0) { flags.insert(.command) } if (mods.rawValue & GHOSTTY_MODS_SUPER.rawValue != 0) { flags.insert(.command) }
if (mods.rawValue & GHOSTTY_MODS_FN.rawValue != 0) { flags.insert(.function) }
return flags return flags
} }
@ -25,6 +26,7 @@ extension Ghostty {
if (flags.contains(.control)) { mods |= GHOSTTY_MODS_CTRL.rawValue } if (flags.contains(.control)) { mods |= GHOSTTY_MODS_CTRL.rawValue }
if (flags.contains(.option)) { mods |= GHOSTTY_MODS_ALT.rawValue } if (flags.contains(.option)) { mods |= GHOSTTY_MODS_ALT.rawValue }
if (flags.contains(.command)) { mods |= GHOSTTY_MODS_SUPER.rawValue } if (flags.contains(.command)) { mods |= GHOSTTY_MODS_SUPER.rawValue }
if (flags.contains(.function)) { mods |= GHOSTTY_MODS_FN.rawValue }
if (flags.contains(.capsLock)) { mods |= GHOSTTY_MODS_CAPS.rawValue } if (flags.contains(.capsLock)) { mods |= GHOSTTY_MODS_CAPS.rawValue }
// Handle sided input. We can't tell that both are pressed in the // Handle sided input. We can't tell that both are pressed in the

View File

@ -726,6 +726,7 @@ extension Ghostty {
case 0x3B, 0x3E: mod = GHOSTTY_MODS_CTRL.rawValue case 0x3B, 0x3E: mod = GHOSTTY_MODS_CTRL.rawValue
case 0x3A, 0x3D: mod = GHOSTTY_MODS_ALT.rawValue case 0x3A, 0x3D: mod = GHOSTTY_MODS_ALT.rawValue
case 0x37, 0x36: mod = GHOSTTY_MODS_SUPER.rawValue case 0x37, 0x36: mod = GHOSTTY_MODS_SUPER.rawValue
case 0x3F: mod = GHOSTTY_MODS_FN.rawValue
default: return default: return
} }

View File

@ -670,9 +670,19 @@ class: ?[:0]const u8 = null,
/// translated by any system keyboard layouts. Example: "ctrl+physical:a" /// translated by any system keyboard layouts. Example: "ctrl+physical:a"
/// ///
/// Valid modifiers are `shift`, `ctrl` (alias: `control`), `alt` (alias: `opt`, /// Valid modifiers are `shift`, `ctrl` (alias: `control`), `alt` (alias: `opt`,
/// `option`), and `super` (alias: `cmd`, `command`). You may use the modifier /// `option`), `super` (alias: `cmd`, `command`), and `function` (alias: `fn`,
/// or the alias. When debugging keybinds, the non-aliased modifier will always /// `globe`). You may use the modifier or the alias. When debugging keybinds,
/// be used in output. /// the non-aliased modifier will always be used in output.
///
/// Some notes about the `function` modifier:
///
/// * It is only available on macOS.
/// * It is used by many system shortcuts and Ghostty is not able to
/// override these shortcuts. If a system shortcut is triggered, the
/// system shortcut will take precedence.
/// * Menu items on macOS cannot be bound to the `function` modifier,
/// so this modifier will work with Ghostty but will not be visible
/// in the menu.
/// ///
/// You may also specify multiple triggers separated by `>` to require a /// You may also specify multiple triggers separated by `>` to require a
/// sequence of triggers to activate the action. For example, /// sequence of triggers to activate the action. For example,

View File

@ -896,9 +896,13 @@ pub const Trigger = struct {
// Alias modifiers // Alias modifiers
const alias_mods = .{ const alias_mods = .{
.{ "cmd", "super" }, .{ "command", "super" }, .{ "cmd", "super" },
.{ "opt", "alt" }, .{ "option", "alt" }, .{ "command", "super" },
.{ "opt", "alt" },
.{ "option", "alt" },
.{ "control", "ctrl" }, .{ "control", "ctrl" },
.{ "fn", "function" },
.{ "globe", "function" },
}; };
inline for (alias_mods) |pair| { inline for (alias_mods) |pair| {
if (std.mem.eql(u8, part, pair[0])) { if (std.mem.eql(u8, part, pair[0])) {

View File

@ -89,10 +89,11 @@ pub const Mods = packed struct(Mods.Backing) {
ctrl: bool = false, ctrl: bool = false,
alt: bool = false, alt: bool = false,
super: bool = false, super: bool = false,
function: bool = false,
caps_lock: bool = false, caps_lock: bool = false,
num_lock: bool = false, num_lock: bool = false,
sides: side = .{}, sides: side = .{},
_padding: u6 = 0, _padding: u5 = 0,
/// Tracks the side that is active for any given modifier. Note /// Tracks the side that is active for any given modifier. Note
/// that this doesn't confirm a modifier is pressed; you must check /// that this doesn't confirm a modifier is pressed; you must check