swiftnsviewappkitfirst-respondernscontrol

First responder on mouse down behavior NSControl and NSView


I have a custom control. If it inherits from NSView, it automatically becomes the first responder when I click on it. If it inherits from NSControl, it does not. This difference in behavior persists, even if I override mouseDown(with:) and don't call super.

Code:

class MyControl: NSView {
  override var canBecomeKeyView: Bool      { return true }
  override var acceptsFirstResponder: Bool { return true }
  override func drawFocusRingMask()        { bounds.fill() }
  override var focusRingMaskBounds: NSRect { return bounds }

  override func draw(_ dirtyRect: NSRect) {
    NSColor.white.set()
    bounds.fill()
  }
}

As you can see, I override acceptsFirstResponder among other methods and properties that are key view and responder related. I have also checked the refusesFirstResponder property. It is set to false.

  1. What is the reason for this difference in behavior?
  2. Is there a method or property that I can override to influence it?
  3. Say I want the behavior where the view becomes the first responder when clicked and the view inherits from NSControl, is calling window!.makeFirstResponder(self) at the beginning of my mouse-down event handler a good solution or is there a better one?

Solution

  • The property to override is needsPanelToBecomeKey.

    A Boolean value indicating whether the view needs its panel to become the key window before it can handle keyboard input and navigation.

    The default value of this property is false. Subclasses can override this property and use their implementation to determine if the view requires its panel to become the key window so that it can handle keyboard input and navigation. Such a subclass should also override acceptsFirstResponder to return true.

    This property is also used in keyboard navigation. It determines if a mouse click should give focus to a view—that is, make it the first responder). Some views (for example, text fields) want to receive the keyboard focus when you click in them. Other views (for example, buttons) receive focus only when you tab to them. You wouldn't want focus to shift from a textfield that has editing in progress simply because you clicked on a check box.

    NSView returns true, NSControl returns false.