From c75009e46f65b45434f7d093cd6b441b7a463978 Mon Sep 17 00:00:00 2001 From: Fedor Korotkov Date: Wed, 8 Nov 2023 11:21:55 -0500 Subject: [PATCH] Introduce `--capture-system-keys` flag (#650) To allow guest to capture things like Cmd+Tab. Fixes #636 --- Sources/tart/Commands/Run.swift | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/Sources/tart/Commands/Run.swift b/Sources/tart/Commands/Run.swift index 230630ef..e0f2fb9d 100644 --- a/Sources/tart/Commands/Run.swift +++ b/Sources/tart/Commands/Run.swift @@ -108,6 +108,10 @@ struct Run: AsyncParsableCommand { @Flag(help: ArgumentHelp("Disables audio and entropy devices and switches to only Mac-specific input devices.", discussion: "Useful for running a VM that can be suspended via \"tart suspend\".")) var suspendable: Bool = false + @Flag(help: ArgumentHelp("Whether system hot keys should be sent to the guest instead of the host", + discussion: "If enabled then system hot keys like Cmd+Tab will be sent to the guest instead of the host.")) + var captureSystemKeys: Bool = false + mutating func validate() throws { if vnc && vncExperimental { throw ValidationError("--vnc and --vnc-experimental are mutually exclusive") @@ -121,6 +125,10 @@ struct Run: AsyncParsableCommand { throw ValidationError("--graphics and --no-graphics are mutually exclusive") } + if (noGraphics || vnc || vncExperimental) && captureSystemKeys { + throw ValidationError("--captures-system-keys can only be used with the default VM view") + } + let localStorage = VMStorageLocal() let vmDir = try localStorage.open(name) if try vmDir.state() == "suspended" { @@ -306,7 +314,7 @@ struct Run: AsyncParsableCommand { if noGraphics || useVNCWithoutGraphics { dispatchMain() } else { - runUI(suspendable) + runUI(suspendable, captureSystemKeys) } } @@ -467,7 +475,7 @@ struct Run: AsyncParsableCommand { return [device] } - private func runUI(_ suspendable: Bool) { + private func runUI(_ suspendable: Bool, _ captureSystemKeys: Bool) { let nsApp = NSApplication.shared nsApp.setActivationPolicy(.regular) nsApp.activate(ignoringOtherApps: true) @@ -476,13 +484,14 @@ struct Run: AsyncParsableCommand { struct MainApp: App { static var disappearSignal: Int32 = SIGINT + static var capturesSystemKeys: Bool = false @NSApplicationDelegateAdaptor private var appDelegate: MinimalMenuAppDelegate var body: some Scene { WindowGroup(vm!.name) { Group { - VMView(vm: vm!).onAppear { + VMView(vm: vm!, capturesSystemKeys: MainApp.capturesSystemKeys).onAppear { NSWindow.allowsAutomaticWindowTabbing = false }.onDisappear { let ret = kill(getpid(), MainApp.disappearSignal) @@ -532,6 +541,7 @@ struct Run: AsyncParsableCommand { } MainApp.disappearSignal = suspendable ? SIGUSR1 : SIGINT + MainApp.capturesSystemKeys = captureSystemKeys MainApp.main() } } @@ -581,14 +591,12 @@ struct VMView: NSViewRepresentable { typealias NSViewType = VZVirtualMachineView @ObservedObject var vm: VM + var capturesSystemKeys: Bool func makeNSView(context: Context) -> NSViewType { let machineView = VZVirtualMachineView() - // Do not capture system keys so that shortcuts like - // Shift-Command-4 + Space (capture a screenshot of window) - // work on the host instead of the guest - machineView.capturesSystemKeys = false + machineView.capturesSystemKeys = capturesSystemKeys // Enable automatic display reconfiguration // for guests that support it