How to make focus work on tvOS simulator?

Despite reading loads of documentation and SO threads, I just can’t make my tvOS app focus change while using the keyboard on the tvOS simulator.

Used config: XCode 15, tvOS 17

Starting point: on the simulator home screen, I can use the arrow keys and the return key to navigate and launch apps.

I just have a simple app with 3 horizontally aligned sprites, and I’d like the arrow keys to navigate between them.

View Controller:

class GameViewController: UIViewController {
    
    // overriding preferredFocusEnvironments to return [scene] doesn't change anything

    override func viewDidLoad() {
        super.viewDidLoad()
        
        if let view = self.view as! SKView? {
            // Load the SKScene from 'GameScene.sks'
            if let scene = SKScene(fileNamed: "GameScene") {
                // Set the scale mode to scale to fit the window
                scene.scaleMode = .aspectFill
                
                /* set or unset doesn't change anything
                scene.focusBehavior             = .focusable
                scene.isUserInteractionEnabled  = true
                */

                // Present the scene
                view.presentScene(scene)
            }
        }
    }
    
    
    override func pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
        print("EVT- press began in controller")
    }
    
    override func pressesChanged(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
        print("EVT- press changed in controller")
    }
    
    override func pressesEnded(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
        print("EVT- press ended in controller")
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("EVT- touch began in controller")
    }
    
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("EVT- touches moved in controller")
    }
    
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("EVT- touches ended in controller")
    }
}

Scene class:

class GameScene: SKScene {
    
    private var button1 : MySpriteNode!
    private var button2 : MySpriteNode!
    private var button3 : MySpriteNode!
    
    //Stef: overriden or not doens't make a difference
//    override var preferredFocusEnvironments: [UIFocusEnvironment] {
//        return [button1, button2, button3]
//    }
    
    
    override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {
        //Stef: called after the didUpdateFocus of the buttons
        print("GameScene::didUpdateFocus")
        print("FOC- Focus is now: (UIScreen.main.focusedItem)")
    }
    
    
    private var label : SKLabelNode?
    private var spinnyNode : SKShapeNode?
    
    override func didMove(to view: SKView) {
        
        self.button1 = self.childNode(withName: "//sprite1") as? MySpriteNode
        self.button1.isUserInteractionEnabled   = true  //set or unset doesn't make a difference
        self.button2 = self.childNode(withName: "//sprite2") as? MySpriteNode
        self.button2.isUserInteractionEnabled   = true
        self.button3 = self.childNode(withName: "//sprite3") as? MySpriteNode
        self.button3.isUserInteractionEnabled   = true
        
        self.isUserInteractionEnabled = true    //set or unset doesn't make a difference
        //  self.becomeFirstResponder() doesn't make any difference
    }
}

Sprite node:

class MySpriteNode: SKSpriteNode {

    override var canBecomeFocused: Bool {
        true
    }

    override var isUserInteractionEnabled: Bool {
        get { true }
        set { }
    }

    override var focusBehavior: SKNodeFocusBehavior {
        get { .focusable }
        set { }
    }

    override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {

        print("SKSpriteNode::didUpdateFocus")
        
        if context.previouslyFocusedItem === self {
            print("FOC- Leaving (self.name!)")
            self.resignFirstResponder()
        }

        if context.nextFocusedItem === self {
             // SKAction to run focus animation for focused button
            print("FOC- Entering (self.name!)")
            self.becomeFirstResponder()
            printResponderChain(from: self)
        }
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("EVT- touch began in sprite")
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("EVT- (self.name!) touched")
    }
    
    override func pressesEnded(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
        print("EVT- (self.name!) pressed")
    }
}

Whatever I do, I always get the same console logs:

SKSpriteNode::didUpdateFocus
FOC- Entering sprite1
Resp: <SKSpriteNode> name:'sprite1' texture:['nil'] position:{-348.35546875, 220.66392517089844} scale:{1.00, 0.37} size:{100, 37.421669006347656} anchor:{0.5, 0.5} rotation:0.00
GameScene::didUpdateFocus
FOC- Focus is now: Optional(<SKSpriteNode> name:'sprite1' texture:['nil'] position:{-348.35546875, 220.66392517089844} scale:{1.00, 0.37} size:{100, 37.421669006347656} anchor:{0.5, 0.5} rotation:0.00)
void * _Nullable NSMapGet(NSMapTable * _Nonnull, const void * _Nullable): map table argument is NULL

I also get a bunch of warnings like this:

Using legacy initializer -[UIFocusRegion initWithFrame:] for region <_UIFocusItemRegion: 0x600001762780> - if this region is initialized by a client, please move over to using the UIFocusItem API. If this region is coming from UIKit, this is a UIKit bug.

As stated by the warning, looks like a UIKit bug.

That shows that Sprite 1 gets the focus, but when I use the arrow keys, the other ones never ever get the focus.

I have tried 3 or 4 Open Source packages, they all date from 2017, and none of them work, I never succeed in having the arrow key to navigate the focus.

What’s the catch ?
Am I missing something huge ?

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật