Key changes: - Fix keyboard input handling for control characters in GhosttyTerminalView - Set consumed_mods correctly (exclude Ctrl/Cmd from consumed mods) - Send unmodified character text for Ctrl+key combinations - Add unshifted_codepoint support for proper key encoding - Add TerminalController with Unix socket API (/tmp/ghosttytabs.sock) - Commands: send, send_key, list_tabs, new_tab, close_tab, select_tab - Supports ctrl-c, ctrl-d, ctrl-z, enter, tab, escape, etc. - Add Python test client and automated test suite - tests/ghosttytabs.py - Python client library - tests/test_ctrl_socket.py - Main Ctrl+C/D test suite (4 tests) - tests/test_signals_auto.py - Standalone PTY signal tests - Update CLAUDE.md with socket API documentation and testing guide - Update .gitignore for Python cache files This fixes Ctrl+C/D not working in apps like claude-code, btop, opencode while continuing to work in simpler apps like htop.
83 lines
2.6 KiB
Swift
83 lines
2.6 KiB
Swift
import SwiftUI
|
|
|
|
@main
|
|
struct GhosttyTabsApp: App {
|
|
@StateObject private var tabManager = TabManager()
|
|
|
|
init() {
|
|
// Start the terminal controller for programmatic control
|
|
// This runs after TabManager is created via @StateObject
|
|
}
|
|
|
|
var body: some Scene {
|
|
WindowGroup {
|
|
ContentView()
|
|
.environmentObject(tabManager)
|
|
.onAppear {
|
|
// Start the Unix socket controller for programmatic access
|
|
TerminalController.shared.start(tabManager: tabManager)
|
|
}
|
|
}
|
|
.windowStyle(.hiddenTitleBar)
|
|
.commands {
|
|
// New tab commands
|
|
CommandGroup(replacing: .newItem) {
|
|
Button("New Tab") {
|
|
tabManager.addTab()
|
|
}
|
|
.keyboardShortcut("t", modifiers: .command)
|
|
|
|
Button("New Tab") {
|
|
tabManager.addTab()
|
|
}
|
|
.keyboardShortcut("n", modifiers: .command)
|
|
|
|
Button("New Tab") {
|
|
tabManager.addTab()
|
|
}
|
|
.keyboardShortcut("`", modifiers: [.control, .shift])
|
|
}
|
|
|
|
// Close tab
|
|
CommandGroup(after: .newItem) {
|
|
Button("Close Tab") {
|
|
tabManager.closeCurrentTab()
|
|
}
|
|
.keyboardShortcut("w", modifiers: .command)
|
|
}
|
|
|
|
// Tab navigation
|
|
CommandGroup(after: .toolbar) {
|
|
Button("Next Tab") {
|
|
tabManager.selectNextTab()
|
|
}
|
|
.keyboardShortcut("]", modifiers: [.command, .shift])
|
|
|
|
Button("Previous Tab") {
|
|
tabManager.selectPreviousTab()
|
|
}
|
|
.keyboardShortcut("[", modifiers: [.command, .shift])
|
|
|
|
Button("Next Tab") {
|
|
tabManager.selectNextTab()
|
|
}
|
|
.keyboardShortcut(.tab, modifiers: .control)
|
|
|
|
Button("Previous Tab") {
|
|
tabManager.selectPreviousTab()
|
|
}
|
|
.keyboardShortcut(.tab, modifiers: [.control, .shift])
|
|
|
|
Divider()
|
|
|
|
// Cmd+1 through Cmd+9 for tab selection
|
|
ForEach(1...9, id: \.self) { number in
|
|
Button("Tab \(number)") {
|
|
tabManager.selectTab(at: number - 1)
|
|
}
|
|
.keyboardShortcut(KeyEquivalent(Character("\(number)")), modifiers: .command)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|