2

I am very new to cocoa and really confused with the whole concept of the first responder. When does an object become a first responder? Assuming each object in my view hierarchy accepts a first responder status, if no explicit "becomeFirstResponder" is made, what is the default first responder after an app is launched?

UPDATED:

I should probably be a bit more specific about my confusion, which stems from the following experiments I did to study the behaviour of first responder.

Experiment 1):

The goal of this experiment is to detect "mouseMoved" from a first responder. According to the spec, "mouseMoved" is always sent to the first responder first.

I constructed the following hierarchy in Xcode:

NSWindow - NSView - myCustomView

myCustomView inherits from NSView and is implemented as follow:

@implementation myView

- (void)awakeFromNib
{
    [[self window] setAcceptsMouseMovedEvents:YES];
}

- (void)drawRect:(NSRect)dirtyRect
{
    [[NSColor blueColor] set];
    NSRectFill([self bounds]);
} 

- (void)mouseMoved:(NSEvent *)theEvent
{
    NSLog(@"[MYCUSTOMVIEW] mouse moved");
}
@end

When I ran the above code, nothing is printed out as I move my mouse on the screen. This is expected, as NSWindow is the first responder. myCustomView never received the "mouseMoved".

Experiment 2):

I added the following to myCustomView's implementation:

- (BOOL)acceptsFirstResponder
{
    return YES;
}

When I ran the code, still nothing is printed out. Now I am confused, shouldn't myCustomView have become the first responder in this case and receive "mouseMoved" event?

What's interesting is, when I clicked the mouse inside the bounds of myCustomView, then the "[MYCUSTOMVIEW] mouse moved" message started to show up in the console. I can understand the clicking action makes myCustomView the first responder, but why wasn't it in the first place?

If I ran the code again, this time, the "[MYCUSTOMVIEW] mouse moved" message showed up right from the beginning. I didn't have to click myCustomView anymore. What is going on?

Experiment 3):

I changed "acceptsFirstResponder" to return "NO" and ran the code. The "[MYCUSTOMVIEW] mouse moved" message still showed up from the beginning. What the! myCustomView is no longer interested in being the first responder. Why is it still receiving "mouseMoved" event?

This is really confusing to me. I will be really appreciated if someone can tell me what is happening above, and how is the first responder set initially at launch?

Thanks!

  • Have a look at [Responder object](https://developer.apple.com/library/ios/documentation/general/conceptual/Devpedia-CocoaApp/Responder.html) – Parag Bafna Nov 16 '13 at 09:47
  • Thanks for the replay. The doc does not seem to explain how the first responder is set initially when an app is launched. I have updated my question. – user2870658 Nov 16 '13 at 12:37
  • 2
    You're looking for the `initialFirstResponder` property of NSWindow, which can be assigned from within Interface Builder. As for the different behavior between runs, your window may be automatically restoring its state: http://stackoverflow.com/questions/7157853/why-does-setting-initialfirstresponder-have-no-effect – Darren Nov 16 '13 at 12:52
  • This is exactly what I was looking for! It is now working the way I expected. Thank you very much! – user2870658 Dec 10 '13 at 07:08

1 Answers1

1

The event chain for mouse events is different from other events — they are always sent to the topmost NSView under the cursor, NOT the first responder. This is good — you would’t want your mouseDown: event to be sent to a text field you’re editing (which would be the firstResponder) if you actually clicked on a button somewhere else in the window.

If you’d like to always get mouse moved events add an NSTrackingArea to the view, like this:

entireViewTrackingArea = NSTrackingArea(rect: .zero, options: [.mouseMoved, .activeInActiveApp, .inVisibleRect], owner: self, userInfo: nil)
addTrackingArea(entireViewTrackingArea!)

I don’t recommend setAcceptsMouseMovedEvents: because it’s kind of extreme for what you want. (You don’t usually want every single view in the window to get mouse moved events, that might be expensive.)

Wil Shipley
  • 9,343
  • 35
  • 59