SwiftUI app runs differently on hardware platforms

I have a simple SwiftUI app that has a picker, textfield and several buttons. It is using a Enum as a focus state for the various controls. When I compile and run it on Mac Studio desktop it works as expected: Picker has initial focus, Selection in Picker changes focus to TextField, Tab key moves through buttons; last button resets to Picker

However when I run the exact same app on MacBook Pro (same version of MacOS, 14.5) it does not work at all as expected. Instead: Initial focus is set to TextField, Tab does not change the focus, Clicking on last button resets focus to TextField rather than Picker

The content view code:


enum FFocus: Hashable {
    case pkNames
    case btnAssign
    case tfValue
    case btn1
    case btn2
    case noFocus
}

struct PZParm: Identifiable {
    var id = 0
    var name = ""
}

struct ContentView: View {
    @State var psel:Int = 0
    @State var tfVal = "Testing"
    
    @FocusState var hwFocus:FFocus?
    
    var body: some View {
        VStack {
            Text("Hardware Test").font(.title2)
            PPDefView(bSel: $psel)
                .focused($hwFocus, equals: .pkNames)
            TextField("testing", text:$tfVal)
                .frame(width: 400)
                .focused($hwFocus, equals: .tfValue)
            HStack {
                Button("Button1", action: {})
                    .frame(width: 150)
                    .focused($hwFocus, equals: .btn1)
                Button("Button2", action: {
                    tfVal = ""
                    hwFocus = .tfValue
                })
                    .frame(width: 150)
                    .focused($hwFocus, equals: .btn2)
                Button("New", action: {
                    tfVal = ""
                    hwFocus = .pkNames
                })
                    .frame(width: 150)
                    .focused($hwFocus, equals: .btnAssign)
            }
        }
        .padding()
        // handle picker change
        .onChange(of: psel, {
            if psel > 0 {hwFocus = .tfValue}
        })
        .onAppear(perform: {hwFocus = .pkNames})
    }
}

#Preview {
    ContentView()
}

struct PPDefView: View {
    @Binding var bSel:Int
    
    // test defs
    let pzparms:[PZParm] = [
        PZParm.init(id:1, name:"Name1"),
        PZParm.init(id:2, name:"Name2")
    ]
    //
    
    var body:some View {
        Picker(selection: $bSel, label: Text("Puzzle Type")) {
            ForEach(pzparms) {Text($0.name)}
                }.frame(width: 250)
    }
}
Answered by alfamsome2 in 791325022

So I think I have found the reason for this difference in behavior on various hardware platforms. It has to do with a System Setting found in the Keyboard settings section named: Keyboard Navigation.

if it is enabled then the program works as expected and if it is disabled then the program doesn't work as expected. In my case, for some reason, my Mac Studio desktop had this setting enabled (so it worked); my MacBook pro had the setting disabled (so it didn't work). When I enabled on MBP it worked; when I disabled on Mac Studio it stopped working.

I tested on MacMini, MacOS 14.5, Xcode 15.3. For what it's worth.

Do you get this error in log:

Picker: the selection "0" is invalid and does not have an associated tag, this will give undefined results.

Replacing

    @State var psel:Int = 0

by

    @State var psel:Int = 1

clears the error

I also get this error when selecting in Picker:

CLIENT ERROR: TUINSRemoteViewController does not override -viewServiceDidTerminateWithError: and thus cannot react to catastrophic errors beyond logging them

yes; I did get that error and changed the initial value to 1;

when you ran on mac mini did it work properly (like my desktop) or not (like MacBook pro)?

I made a few other changes to the code also (to display the hardware name, etc); updated code for Content View: (not sure how to edit original post)


enum FFocus: Hashable {
    case pkNames
    case btnAssign
    case tfValue
    case btn1
    case btn2
    case noFocus
}

struct PZParm: Identifiable {
    var id = 0
    var name = ""
}

struct ContentView: View {
    @State var psel:Int = 0
    @State var tfVal = "Testing"
    @State var hw = ""
    
    @FocusState var hwFocus:FFocus?
    
    var body: some View {
        VStack {
            Text("Hardware test on " + hw).font(.title2)
            PPDefView(bSel: $psel)
                .focused($hwFocus, equals: .pkNames)
            TextField("testing", text:$tfVal)
                .frame(width: 400)
                .focused($hwFocus, equals: .tfValue)
            HStack {
                Button("Button1", action: {})
                    .frame(width: 150)
                    .focused($hwFocus, equals: .btn1)
                Button("Button2", action: {
                    tfVal = ""
                    hwFocus = .tfValue
                })
                    .frame(width: 150)
                    .focused($hwFocus, equals: .btn2)
                Button("New", action: {
                    tfVal = ""
                    psel = 0
                    hwFocus = .pkNames
                })
                    .frame(width: 150)
                    .focused($hwFocus, equals: .btnAssign)
            }
        }
        .padding()
        // handle picker change
        .onChange(of: psel, {
            if psel > 0 {hwFocus = .tfValue}
        })
        .onAppear(perform: {
            hw = hwn()
            hwFocus = .pkNames}
        )
    }
    
    // generate hardware model name
    //  using sysctlbyname
    //
    func hwn() -> String {
        var len = 0
        sysctlbyname("hw.model", nil, &len, nil, 0)
        if len > 0 {
            var rawName = Array<UInt8>(repeating: 0, count: len)
            sysctlbyname("hw.model", &rawName, &len, nil, 0)
            if let s = String(bytes: rawName, encoding: .utf8) {
                return s
            }
        }
        return "Unknown"
    }
}

#Preview {
    ContentView()
}

struct PPDefView: View {
    @Binding var bSel:Int
    
    // test defs
    let pzparms:[PZParm] = [
        PZParm.init(id:1, name:"Name1"),
        PZParm.init(id:2, name:"Name2"),
        PZParm.init(id:3, name:"Name3")
    ]
    //
    
    var body:some View {
        Picker(selection: $bSel, label: Text("Name")) {
            if bSel == 0 {
                Text("no selection").tag(0)
            }
            ForEach(pzparms) {Text($0.name)}
                }.frame(width: 250)
    }
}
Accepted Answer

So I think I have found the reason for this difference in behavior on various hardware platforms. It has to do with a System Setting found in the Keyboard settings section named: Keyboard Navigation.

if it is enabled then the program works as expected and if it is disabled then the program doesn't work as expected. In my case, for some reason, my Mac Studio desktop had this setting enabled (so it worked); my MacBook pro had the setting disabled (so it didn't work). When I enabled on MBP it worked; when I disabled on Mac Studio it stopped working.

SwiftUI app runs differently on hardware platforms
 
 
Q