bd44b5aa08
Test / build-libghostty-vt (x86_64-windows-gnu) (push) Has been cancelled
Test / build-libghostty-vt-macos (aarch64-ios) (push) Has been cancelled
Test / build-libghostty-vt-macos (aarch64-macos) (push) Has been cancelled
Test / build-libghostty-vt-macos (x86_64-macos) (push) Has been cancelled
Test / build-nix (namespace-profile-ghostty-md-arm64) (push) Has been cancelled
Test / build-dist (push) Has been cancelled
Test / GTK x11=true wayland=true (push) Has been cancelled
Test / Build -Dsimd=false (push) Has been cancelled
Test / Build -Dsimd=true (push) Has been cancelled
Test / Build -Dsentry=false (push) Has been cancelled
Test / Build -Dsentry=true (push) Has been cancelled
Test / zig-fmt (push) Has been cancelled
Test / GitHub Actions Pins (push) Has been cancelled
Test / prettier (push) Has been cancelled
Test / swiftlint (push) Has been cancelled
Test / alejandra (push) Has been cancelled
Test / typos (push) Has been cancelled
Nix / Required Checks: Nix (push) Has been cancelled
Nix / check-zig-cache-hash (push) Has been cancelled
Test / skip (push) Has been cancelled
Test / Required Checks: Test (push) Has been cancelled
Test / build-bench (push) Has been cancelled
Test / list-examples (push) Has been cancelled
Test / Example ${{ matrix.dir }} (Windows) (push) Has been cancelled
Test / build-cmake (push) Has been cancelled
Test / test-lib-vt-pkgconfig (push) Has been cancelled
Test / build-flatpak (push) Has been cancelled
Test / build-snap (push) Has been cancelled
Test / build-libghostty-vt (aarch64-linux) (push) Has been cancelled
Test / build-libghostty-vt (aarch64-macos) (push) Has been cancelled
Test / build-libghostty-vt (wasm32-freestanding) (push) Has been cancelled
Test / build-libghostty-vt (x86_64-linux) (push) Has been cancelled
Test / build-libghostty-vt (x86_64-linux-musl) (push) Has been cancelled
Test / build-libghostty-vt (x86_64-macos) (push) Has been cancelled
Test / build-libghostty-vt-android (aarch64-linux-android) (push) Has been cancelled
Test / build-libghostty-vt-android (arm-linux-androideabi) (push) Has been cancelled
Test / build-libghostty-vt-android (x86_64-linux-android) (push) Has been cancelled
Test / build-libghostty-vt-windows (push) Has been cancelled
Test / build-libghostty-windows-gnu (push) Has been cancelled
Test / build-linux (namespace-profile-ghostty-md) (push) Has been cancelled
Test / build-linux (namespace-profile-ghostty-md-arm64) (push) Has been cancelled
Test / build-linux-libghostty (push) Has been cancelled
Test / build-nix (namespace-profile-ghostty-md) (push) Has been cancelled
Test / build-dist-lib-vt (push) Has been cancelled
Test / trigger-snap (push) Has been cancelled
Test / trigger-flatpak (push) Has been cancelled
Test / build-macos (push) Has been cancelled
Test / build-macos-freetype (push) Has been cancelled
Test / test (push) Has been cancelled
Test / test-lib-vt (push) Has been cancelled
Test / GTK x11=false wayland=false (push) Has been cancelled
Test / GTK x11=true wayland=false (push) Has been cancelled
Test / GTK x11=false wayland=true (push) Has been cancelled
Test / test-macos (push) Has been cancelled
Test / test-windows (push) Has been cancelled
Test / Build -Di18n=false (push) Has been cancelled
Test / Build -Di18n=true (push) Has been cancelled
Test / Build test/fuzz-libghostty (push) Has been cancelled
Test / shellcheck (push) Has been cancelled
Test / translations (push) Has been cancelled
Test / blueprint-compiler (push) Has been cancelled
Test / Test pkg/wuffs (push) Has been cancelled
Test / Test build on Debian 13 (push) Has been cancelled
Test / valgrind (push) Has been cancelled
Test / Example ${{ matrix.dir }} (push) Has been cancelled
328 lines
8.8 KiB
Swift
328 lines
8.8 KiB
Swift
import AppKit
|
|
import AppIntents
|
|
|
|
/// App intent to input text in a terminal.
|
|
struct InputTextIntent: AppIntent {
|
|
static var title: LocalizedStringResource = "Input Text to Terminal"
|
|
|
|
@Parameter(
|
|
title: "Text",
|
|
description: "The text to input to the terminal. The text will be inputted as if it was pasted.",
|
|
inputOptions: String.IntentInputOptions(
|
|
capitalizationType: .none,
|
|
multiline: true,
|
|
autocorrect: false,
|
|
smartQuotes: false,
|
|
smartDashes: false
|
|
)
|
|
)
|
|
var text: String
|
|
|
|
@Parameter(
|
|
title: "Terminal",
|
|
description: "The terminal to scope this action to."
|
|
)
|
|
var terminal: TerminalEntity
|
|
|
|
#if compiler(>=6.2)
|
|
@available(macOS 26.0, *)
|
|
static var supportedModes: IntentModes = [.background, .foreground]
|
|
#endif
|
|
|
|
@MainActor
|
|
func perform() async throws -> some IntentResult {
|
|
guard await requestIntentPermission() else {
|
|
throw GhosttyIntentError.permissionDenied
|
|
}
|
|
|
|
guard let surface = terminal.surfaceModel else {
|
|
throw GhosttyIntentError.surfaceNotFound
|
|
}
|
|
|
|
surface.sendText(text)
|
|
return .result()
|
|
}
|
|
}
|
|
|
|
/// App intent to trigger a keyboard event.
|
|
struct KeyEventIntent: AppIntent {
|
|
static var title: LocalizedStringResource = "Send Keyboard Event to Terminal"
|
|
static var description = IntentDescription("Simulate a keyboard event. This will not handle text encoding; use the 'Input Text' action for that.")
|
|
|
|
@Parameter(
|
|
title: "Key",
|
|
description: "The key to send to the terminal.",
|
|
default: .enter
|
|
)
|
|
var key: Ghostty.Input.Key
|
|
|
|
@Parameter(
|
|
title: "Modifier(s)",
|
|
description: "The modifiers to send with the key event.",
|
|
default: []
|
|
)
|
|
var mods: [KeyEventMods]
|
|
|
|
@Parameter(
|
|
title: "Event Type",
|
|
description: "A key press or release.",
|
|
default: .press
|
|
)
|
|
var action: Ghostty.Input.Action
|
|
|
|
@Parameter(
|
|
title: "Terminal",
|
|
description: "The terminal to scope this action to."
|
|
)
|
|
var terminal: TerminalEntity
|
|
|
|
#if compiler(>=6.2)
|
|
@available(macOS 26.0, *)
|
|
static var supportedModes: IntentModes = [.background, .foreground]
|
|
#endif
|
|
|
|
@MainActor
|
|
func perform() async throws -> some IntentResult {
|
|
guard await requestIntentPermission() else {
|
|
throw GhosttyIntentError.permissionDenied
|
|
}
|
|
|
|
guard let surface = terminal.surfaceModel else {
|
|
throw GhosttyIntentError.surfaceNotFound
|
|
}
|
|
|
|
// Convert KeyEventMods array to Ghostty.Input.Mods
|
|
let ghosttyMods = mods.reduce(Ghostty.Input.Mods()) { result, mod in
|
|
result.union(mod.ghosttyMod)
|
|
}
|
|
|
|
let keyEvent = Ghostty.Input.KeyEvent(
|
|
key: key,
|
|
action: action,
|
|
mods: ghosttyMods
|
|
)
|
|
surface.sendKeyEvent(keyEvent)
|
|
|
|
return .result()
|
|
}
|
|
}
|
|
|
|
// MARK: MouseButtonIntent
|
|
|
|
/// App intent to trigger a mouse button event.
|
|
struct MouseButtonIntent: AppIntent {
|
|
static var title: LocalizedStringResource = "Send Mouse Button Event to Terminal"
|
|
|
|
@Parameter(
|
|
title: "Button",
|
|
description: "The mouse button to press or release.",
|
|
default: .left
|
|
)
|
|
var button: Ghostty.Input.MouseButton
|
|
|
|
@Parameter(
|
|
title: "Action",
|
|
description: "Whether to press or release the button.",
|
|
default: .press
|
|
)
|
|
var action: Ghostty.Input.MouseState
|
|
|
|
@Parameter(
|
|
title: "Modifier(s)",
|
|
description: "The modifiers to send with the mouse event.",
|
|
default: []
|
|
)
|
|
var mods: [KeyEventMods]
|
|
|
|
@Parameter(
|
|
title: "Terminal",
|
|
description: "The terminal to scope this action to."
|
|
)
|
|
var terminal: TerminalEntity
|
|
|
|
#if compiler(>=6.2)
|
|
@available(macOS 26.0, *)
|
|
static var supportedModes: IntentModes = [.background, .foreground]
|
|
#endif
|
|
|
|
@MainActor
|
|
func perform() async throws -> some IntentResult {
|
|
guard await requestIntentPermission() else {
|
|
throw GhosttyIntentError.permissionDenied
|
|
}
|
|
|
|
guard let surface = terminal.surfaceModel else {
|
|
throw GhosttyIntentError.surfaceNotFound
|
|
}
|
|
|
|
// Convert KeyEventMods array to Ghostty.Input.Mods
|
|
let ghosttyMods = mods.reduce(Ghostty.Input.Mods()) { result, mod in
|
|
result.union(mod.ghosttyMod)
|
|
}
|
|
|
|
let mouseEvent = Ghostty.Input.MouseButtonEvent(
|
|
action: action,
|
|
button: button,
|
|
mods: ghosttyMods
|
|
)
|
|
surface.sendMouseButton(mouseEvent)
|
|
|
|
return .result()
|
|
}
|
|
}
|
|
|
|
/// App intent to send a mouse position event.
|
|
struct MousePosIntent: AppIntent {
|
|
static var title: LocalizedStringResource = "Send Mouse Position Event to Terminal"
|
|
static var description = IntentDescription("Send a mouse position event to the terminal. This reports the cursor position for mouse tracking.")
|
|
|
|
@Parameter(
|
|
title: "X Position",
|
|
description: "The horizontal position of the mouse cursor in pixels.",
|
|
default: 0
|
|
)
|
|
var x: Double
|
|
|
|
@Parameter(
|
|
title: "Y Position",
|
|
description: "The vertical position of the mouse cursor in pixels.",
|
|
default: 0
|
|
)
|
|
var y: Double
|
|
|
|
@Parameter(
|
|
title: "Modifier(s)",
|
|
description: "The modifiers to send with the mouse position event.",
|
|
default: []
|
|
)
|
|
var mods: [KeyEventMods]
|
|
|
|
@Parameter(
|
|
title: "Terminal",
|
|
description: "The terminal to scope this action to."
|
|
)
|
|
var terminal: TerminalEntity
|
|
|
|
#if compiler(>=6.2)
|
|
@available(macOS 26.0, *)
|
|
static var supportedModes: IntentModes = [.background, .foreground]
|
|
#endif
|
|
|
|
@MainActor
|
|
func perform() async throws -> some IntentResult {
|
|
guard await requestIntentPermission() else {
|
|
throw GhosttyIntentError.permissionDenied
|
|
}
|
|
|
|
guard let surface = terminal.surfaceModel else {
|
|
throw GhosttyIntentError.surfaceNotFound
|
|
}
|
|
|
|
// Convert KeyEventMods array to Ghostty.Input.Mods
|
|
let ghosttyMods = mods.reduce(Ghostty.Input.Mods()) { result, mod in
|
|
result.union(mod.ghosttyMod)
|
|
}
|
|
|
|
let mousePosEvent = Ghostty.Input.MousePosEvent(
|
|
x: x,
|
|
y: y,
|
|
mods: ghosttyMods
|
|
)
|
|
surface.sendMousePos(mousePosEvent)
|
|
|
|
return .result()
|
|
}
|
|
}
|
|
|
|
/// App intent to send a mouse scroll event.
|
|
struct MouseScrollIntent: AppIntent {
|
|
static var title: LocalizedStringResource = "Send Mouse Scroll Event to Terminal"
|
|
static var description = IntentDescription("Send a mouse scroll event to the terminal with configurable precision and momentum.")
|
|
|
|
@Parameter(
|
|
title: "X Scroll Delta",
|
|
description: "The horizontal scroll amount.",
|
|
default: 0
|
|
)
|
|
var x: Double
|
|
|
|
@Parameter(
|
|
title: "Y Scroll Delta",
|
|
description: "The vertical scroll amount.",
|
|
default: 0
|
|
)
|
|
var y: Double
|
|
|
|
@Parameter(
|
|
title: "High Precision",
|
|
description: "Whether this is a high-precision scroll event (e.g., from trackpad).",
|
|
default: false
|
|
)
|
|
var precision: Bool
|
|
|
|
@Parameter(
|
|
title: "Momentum Phase",
|
|
description: "The momentum phase for inertial scrolling.",
|
|
default: Ghostty.Input.Momentum.none
|
|
)
|
|
var momentum: Ghostty.Input.Momentum
|
|
|
|
@Parameter(
|
|
title: "Terminal",
|
|
description: "The terminal to scope this action to."
|
|
)
|
|
var terminal: TerminalEntity
|
|
|
|
#if compiler(>=6.2)
|
|
@available(macOS 26.0, *)
|
|
static var supportedModes: IntentModes = [.background, .foreground]
|
|
#endif
|
|
|
|
@MainActor
|
|
func perform() async throws -> some IntentResult {
|
|
guard await requestIntentPermission() else {
|
|
throw GhosttyIntentError.permissionDenied
|
|
}
|
|
|
|
guard let surface = terminal.surfaceModel else {
|
|
throw GhosttyIntentError.surfaceNotFound
|
|
}
|
|
|
|
let scrollEvent = Ghostty.Input.MouseScrollEvent(
|
|
x: x,
|
|
y: y,
|
|
mods: .init(precision: precision, momentum: momentum)
|
|
)
|
|
surface.sendMouseScroll(scrollEvent)
|
|
|
|
return .result()
|
|
}
|
|
}
|
|
|
|
// MARK: Mods
|
|
|
|
enum KeyEventMods: String, AppEnum, CaseIterable {
|
|
case shift
|
|
case control
|
|
case option
|
|
case command
|
|
|
|
static var typeDisplayRepresentation = TypeDisplayRepresentation(name: "Modifier Key")
|
|
|
|
static var caseDisplayRepresentations: [KeyEventMods: DisplayRepresentation] = [
|
|
.shift: "Shift",
|
|
.control: "Control",
|
|
.option: "Option",
|
|
.command: "Command"
|
|
]
|
|
|
|
var ghosttyMod: Ghostty.Input.Mods {
|
|
switch self {
|
|
case .shift: .shift
|
|
case .control: .ctrl
|
|
case .option: .alt
|
|
case .command: .super
|
|
}
|
|
}
|
|
}
|