I am suspecting that setting GCController.shouldMonitorBackgroundEvents = true
does not actually make the game controllers inputs accessible to the app when it is in the background.
About this value the official documentation says:
A Boolean value that indicates whether the app needs to respond to controller events when it isn’t the frontmost app.
Now the behavior is that when the app is in focus the users inputs do get correctly recognized but as soon as the app enters the background no inputs get recognized. The controller does not get reported as disconnecting and still works for example in launchpad.
I am sure that about 2 months ago when I first used this it did work as one would expect. I also have seen that an app which lets users execute certain actions using their controller has stoped working recently, adding to my suspicion of the feature being broken.
Here is a minimum reproducible example:
import SwiftUI
import GameController
@main
struct TestingControllerConnectionApp: App {
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
class AppDelegate: NSObject, NSApplicationDelegate {
var statusItem: NSStatusItem?
var controller: GCController?
func applicationDidFinishLaunching(_ notification: Notification) {
setupMenuBar()
GCController.shouldMonitorBackgroundEvents = true
NotificationCenter.default.addObserver(
self,
selector: #selector(controllerDidConnect),
name: .GCControllerDidConnect,
object: nil
)
NotificationCenter.default.addObserver(
self,
selector: #selector(controllerDidDisconnect),
name: .GCControllerDidDisconnect,
object: nil
)
}
@objc private func setupMenuBar() {
let menu = NSMenu()
menu.addItem(NSMenuItem(title: "Quit", action: #selector(quitApp), keyEquivalent: "q"))
statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
statusItem?.button?.image = NSImage(resource: .controllerBar)
statusItem?.menu = menu
}
@objc private func quitApp() {
NSApp.terminate(nil)
}
@objc private func controllerDidConnect(_ notification: Notification) {
if let controller = notification.object as? GCController {
print("Controller connected")
self.controller = controller
if let gamepad = controller.extendedGamepad {
gamepad.buttonA.pressedChangedHandler = { _, _, pressed in
print("Button A pressed: \(pressed)")
}
}
}
}
@objc private func controllerDidDisconnect(_ notification: Notification) {
print("Controller disconnected")
}
}
This is created in a completely fresh Xcode project and NSHumanInterfaceDeviceUsageDescription has been added. I am using a PS5 Controller and a Mac running MacOS 15.4.1 which has been restarted and only Xcode and the app have been opened.
I have tested this with setting a multitude of different entitlements and capabilities including:
- NSHumanInterfaceDeviceUsageDescription
- Supports Controller User Interaction
- Required background modes -> App communicates with an accessory
- com.apple.security.device.bluetooth
- com.apple.security.device.hid
- com.apple.security.device.usb
I have also set this value at different points in the code with no change of effect.
Does anybody see if there is any fault in my code or my understanding of the effect of the value 'shouldMonitorBackgroundEvents'? Or is this the functionality actually being broken on Apples part?