Direction that NSView received focus (tab or backtab)?

404 Views Asked by At

I have a custom view that has multiple components that can receive the focus, similar to NSDatePicker in the textFieldAndStepper style. If it gets the focus the first component is focused. You can then tab through the components. If you hit tab while the last component has the focus, the next view in the window gets the focus. When you use backtab (shift + tab) it goes in the other direction. How would I do that?

I currently move the focus along the components in the keyDown event, and I override becomeFirstResponder and resignFirstResponder to switch on or switch off the focus when the user tabs beyond the last component or backtabs beyond the first component.

However in becomeFirstResponder I cannot tell how the view got the focus. It could have been a tab or a backtab or a mouse click.

How do I get this information in becomeFirstResponder, or is there another way to solve this problem.

Note that I don't want to introduce subviews, for various reasons.

Here is the code I have so far:

private var selectedComponent: Int?

override public var acceptsFirstResponder: Bool {
  get { return true }
}

override public func becomeFirstResponder() -> Bool {
  selectedComponent = 0
  needsDisplay = true
  return true
}

override public func resignFirstResponder() -> Bool {
  selectedComponent = nil
  needsDisplay = true
  return true
}

override public func keyDown(with event: NSEvent) {
  guard let selectedComponent = selectedComponent else {
    self.nextResponder?.keyDown(with: event)
    return
  }

  guard let specialKey = event.specialKey else {
    self.nextResponder?.keyDown(with: event)
    return
  }

  if specialKey == NSEvent.SpecialKey.tab && selectedComponent < componentFormats.count - 1 {
    self.selectedComponent = selectedComponent + 1
    needsDisplay = true
  } else if specialKey == NSEvent.SpecialKey.backTab && selectedComponent > 0 {
    self.selectedComponent = selectedComponent - 1
    needsDisplay = true
  } else {
    self.nextResponder?.keyDown(with: event)
  }
}
1

There are 1 best solutions below

2
On

It sounds like you do have your problem sorted out now. But, I was thinking, would it be possible to get the same effect by overriding NSView's nextKeyView and previousKeyView? This should provide the directionality you need, but also might interact better with the system overall (ie Accessibility) than just via keydowns.