Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to determine whether an NSSearchField/NSTextField has input focus?

Tags:

macos

cocoa

How can I determine whether an NSSearchField/NSTextField has input focus?

like image 921
Jake Petroules Avatar asked May 14 '11 00:05

Jake Petroules


2 Answers

AppKit uses a “field editor” (which is an NSTextView) to handle the actual editing in an NSTextField (or an NSSearchField or an NSSecureTextField). While your text field has keyboard focus for its window, it has the field editor as a subview, and the window's first responder is the field editor.

So in general, you can check whether the text field has a field editor:

if textField.currentEditor() != nil {
    // textField has the keyboard focus
} else {
    // textField does not have the keyboard focus
}

However, when you move the focus out of the text field (by pressing the tab key or clicking in another text field), the text field posts an NSControl.textDidEndEditingNotification (Objective-C: NSControlTextDidEndEditingNotification). If the text field has a delegate, and the delegate implements the control(_:controlTextDidEndEditing:) method of the NSControlTextEditingDelegate protocol, then the delegate method is also called for the notification.

While this notification is being delivered (including calling the delegate method), the text field still has the field editor as a subview, and the field editor's delegate is still set to the text field. So if you don't want to consider the text field to still have the keyboard focus while in the notification handler (or delegate method), then testing the field editor will give the wrong answer.

(You might think this is a weird thing to test, because after all AppKit is sending you a notification that the text field is no longer the keyboard focus, so why do you need to ask? But maybe your notification handler calls into some other method that wants to check, and you don't want to have to pass in a flag saying “oh by the way the text field is/isn't the keyboard focus right now”.)

Okay, so anyway, before sending the NSControl.textDidEndEditingNotification, AppKit changes the text field's window's first responder. So you can check whether the text field has a field editor, and whether that field editor is the first responder of its window. While you are handling the NSControl.textDidEndEditingNotification, this test will report that the text field doesn't have the keyboard focus.

extension NSTextField {
    public var hasKeyboardFocus: Bool {
        guard
            let editor = currentEditor(),
            editor == window?.firstResponder
            else { return false }
        return true
    }
}
like image 199
rob mayoff Avatar answered Sep 19 '22 20:09

rob mayoff


The previous answer is wrong, because NSTextField / NSSearchField do not themselves become the first responder and handle edited text. Instead, they use the window's field editor, which is an NSTextView that is shared between all fields on the window (since only one of them can have focus at a time).

You need to see if the first responder is an NSText, and if so, if the search field / text field is its delegate.

NSResponder *firstResponder = [[NSApp keyWindow] firstResponder];
if ([firstResponder isKindOfClass:[NSText class]] && [(id)firstResponder delegate] == mySearchField) {
    NSLog(@"Yup.");
}
like image 31
Greg Titus Avatar answered Sep 20 '22 20:09

Greg Titus