1

Each time the user presses enter, a new NSTextView is made. This works correctly, and the new NSTextView becomes the first responder, as is my goal. However, the cursor does not move into the new NSTextView despite it being the first responder.

Below is my code:

 func makeNSView(context: NSViewRepresentableContext<TextView>) -> TextView.NSViewType {
        let textView = NSTextView()
        textView.textContainer?.lineFragmentPadding = 10
        textView.textContainerInset = .zero
        textView.font = NSFont.systemFont(ofSize: 12)
        textView.becomeFirstResponder()
        //NSApp.activate(ignoringOtherApps: true) ----> doesn't make difference but is supposed to help switch cursor
        print("\(textView) is first responder") //proof that the first responder is shifting, but the cursor does not move with it for some reason
        return textView
    }

I have tried to use this line as suggested by a different answer:

NSApp.activate(ignoringOtherApps: true)

However, it doesn't make any difference. I have also tried inserting text at a selected range, but it doesn't insert text in any of the NSTextViews displayed regardless of whether they are the first responder.

What methods exist to move the cursor to a different NSTextView (preferably to the First Responder)?

Let me know if any more information is needed.

Ken Thomases
  • 88,520
  • 7
  • 116
  • 154
  • 1
    Your view isn’t part of the view hierarchy when you ask it to become first responder. Become first responder after you add the textview to the window – Warren Burton Jun 07 '20 at 18:44

2 Answers2

1

I was able to get the desired behaviour by doing this:

  func makeNSView(context: NSViewRepresentableContext<TextView>) -> TextView.NSViewType {
        let textView = NSTextView()
        textView.textContainer?.lineFragmentPadding = 10
        textView.textContainerInset = .zero
        textView.font = NSFont.systemFont(ofSize: 12)
        DispatchQueue.main.async {textView.window?.makeFirstResponder(textView)
            textView.setSelectedRange(NSMakeRange(0, 0)) }

        print("\(textView) is first responder") //proof that the first responder is shifting, but the cursor does not for some reason
        return textView
    }

The answer originally comes from here: How to make first responder in SwiftUI macOS

Thanks for all the help!

0

As Warren Burton mentions in a comment, you have not added the new view to a window's view hierarchy at the point that you're trying to make it the first responder. That can't work.

Furthermore, calling becomeFirstResponder() does not make the receiver the first responder. (This is different from UIKit.) In fact, you're never supposed to call becomeFirstResponder() on macOS (except to forward to the superclass in an override). The documentation calls this out specifically:

Use the NSWindow makeFirstResponder(_:) method, not this method, to make an object the first responder. Never invoke this method directly.

(Emphasis added.) becomeFirstResponder() is called by Cocoa to inform a view (or other responder) that it has become the first responder. It doesn't cause a change, it notifies about a change.

So, once the view has been added to a window's view hierarchy, invoke textView.window.makeFirstResponder(textView).

Ken Thomases
  • 88,520
  • 7
  • 116
  • 154
  • Hello, thank you for your answer! I added textView.window?.makeFirstResponder(textView) in place of textView.becomeFirstResponder(). However, the result is the same; the cursor doesn't move. How do I explicitly add the view to the window's view hierarchy? I'm probably missing that step. – Chidinma Umenwofor-Nweze Jun 07 '20 at 19:58
  • Typically, you add it as a subview of a view that's already part of the window's view hierarchy. You must be doing that somewhere if the new text view is appearing on screen. – Ken Thomases Jun 07 '20 at 20:01
  • Hmm, this above code is actually in a wrapper for NSTextView so I can use it in SwiftUI. So I'm guessing that the view is being added to the window behind the scenes. Do you know of any function in SwiftUI that will explicitly add a new view to the window's hierarchy? – Chidinma Umenwofor-Nweze Jun 07 '20 at 20:23