Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting when NSTextField becomes active

To be specific I would like to receive notifications when an NSTextField gets focus, or when the user clicks on it and is about to start editing.

I've tried the textDidBeginEditing: method but this is only fired when the user actually starts to type and I need it when the text field becomes the first responder.

I've tried overriding -(BOOL)becomeFirstResponder but that's only called when the text field first becomes the first responder and not any time after that.

I've tried registering for NSControlDidBeginEditing notifications but never got any.

Is this possible?

like image 687
Rob Sanders Avatar asked Jan 17 '16 16:01

Rob Sanders


2 Answers

Implement the window's delegate method windowWillReturnFieldEditor:toObject:. This tells you that the field editor is switching to a different object. Look to see if this object is the text field.

Alternatively, subclass NSWindow and override makeFirstResponder:. Call super, look to see what responder is becoming first responder and whether the call to super returned YES, and return the result of the call to super.

like image 176
matt Avatar answered Nov 11 '22 07:11

matt


Just to be clear @matt's answer put me on the right path; I thought I just ought to clarify exactly how you can do this.

Aim

So I wanted to have an NSTextField subclass that would know when it became active (i.e. first responder), and then notify it's delegate.

Problem

It turns out the under the hood of OS X text editing is a messy world and you can't really rely on NSTextField to do it all. Basically when an object that is involved in text editing becomes the first responder, something (the window, the system, the NSApplication) gives it an _NSKeyboardClipView (I think it's called that...) as a subview. In turn the _NSKeyboardClipView has an NSTextView as a subview, and it's the NSTextView that becomes the first responder.

Solution

• Subclass (or extend) NSWindow and override the makeFirstResponder: method.

• Fire a notification using NSNotificationCenter who's object is the responder object that is passed to the makeFirstResponder: method.

• Catch the notification in your NSTextField subclass.

• Here's the horrible bit: you need to check that the notification.object is, a) a subclass of NSView and, b) the notification.object.superview.superview == self (you will have to cast to NSView here because the object will be of type id). e.g:

- (void)didBecomeFirstResponder:(NSNotification *)note
{
    if ([note.object isKindOfClass:[NSView class]] && [[(NSView *)note.object superview] superview] == self) {
        // You just became the first responder
    }
}

It's horrible and tacky/hacky but it does work.

like image 26
Rob Sanders Avatar answered Nov 11 '22 07:11

Rob Sanders