Estoy escribiendo una pequeña aplicación de barra de estado, que incluye una entrada de texto.
La aplicación se agrega a la barra de estado como un NSMenuItem que contiene un NSHostingViewController con SwiftUI-View. El menú de la barra de estado se agrega a través de un delegado de la aplicación dentro de la escena @principal de SwiftUI. Establecí "La aplicación es un agente" en info.plist en verdadero y tengo una escena vacía como @main en SwiftUI.
Problema: cuando trato de editar texto, en la aplicación de la barra de estado, no se puede hacer clic en el campo de texto y no recibe entrada de texto. Cuando agrego una ventana, el campo de texto en la aplicación de la barra de estado funciona como se esperaba siempre que la ventana esté en primer plano.
Según tengo entendido, esto se debe a que el campo de texto no está dentro de una ventana marcada como ventana clave. ¿Hay alguna solución para que el campo de texto funcione como se espera sin necesidad de una ventana de aplicación adicional?
Ejemplo mínimo para el delegado de la aplicación:
class AppDelegate: NSObject, NSApplicationDelegate { private var statusItem: NSStatusItem? func applicationDidFinishLaunching(_ notification: Notification) { self.statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) if let statusBarButton = statusItem?.button { statusBarButton.image = NSImage(systemSymbolName: "6.circle", accessibilityDescription: "") statusBarButton.image?.isTemplate = true } let menuItem = NSMenuItem() menuItem.view = createView() let menu = NSMenu() menu.addItem(menuItem) statusItem?.menu = menu } private func createView() -> NSView { let view = HostingView(rootView: ContentView()) view.frame = NSRect(x: 0, y: 0, width: 520, height: 260) return view } }SwiftUI @principal
import SwiftUI import AppKit @main struct MacApp: App { @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate var body: some Scene { Settings { EmptyView() } } }Editar: descubrí que hay dos ventanas registradas para mi aplicación. Uno para el icono de la barra de estado y otro para el menú. Sin embargo, el siguiente código no hace que la ventana del menú se convierta en la ventana clave. (aunque de hecho es la única ventana que devuelve verdadero para .canBecomeKey)
.onAppear { let window = NSApp.windows.first { $0.canBecomeKey } window?.makeKey() }Segunda edición: Aparentemente, el problema no es que la ventana no pueda convertirse en clave, sino que la aplicación no está configurada como la aplicación activa cuando se abre el menú de la barra de estado. Se me ocurrió este truco bastante feo, que hace que el menú se cierre y se vuelva a abrir cuando otra aplicación estaba enfocada antes, pero al menos los botones y campos de texto funcionan como se esperaba con esto:
func applicationDidFinishLaunching(_ notification: Notification) { ... // Also let AppDelegate implement NSMenuDelegate menu.delegate = self ... } func menuWillOpen(_ menu: NSMenu) { #warning("This is a hack to activate the app when the menu is shown. This will cause the menu to close and re-open when another window was focused before.") if !NSApp.isActive { NSApp.activate(ignoringOtherApps: true) DispatchQueue.main.async { self.statusItem?.button?.performClick(nil) } } }Todavía estoy buscando una solución adecuada.