Hi all
I am reading up about the responder chain and how to insert custom objects into the responder chain. But this is only working partially.
Maybe you know the answer?
I added a NSView to a xib file. Connected the NSView to a NSViewController and added a CALayer to the NSView. The idea is to have a responder chain like this: CALayer > NSViewController > NSView > NSWindow. The CALayer should respond first to all mouse and key events.
What I learned so far:
NSView and NSViewController are subclasses of NSResponder. However, NSViewController is not automatically part of the responder chain.
CALayer is a subclass of NSObject and therefore never automatically part of the responder chain.
To each of my subclasses of these three objects, I added
The NSViewController injects itself into the responder chain via awakeFromNib
When clicking on the layer, it too gets added to the responder chain via the mouseDown function in MyViewController.
MyViewController also implements these functions.
Mouse and key events work fine when NSViewController is part of the responder chain.
Now, lets implement CALayer _like_ a NSReponder subclass.
Methods that are not implemented will give a "unrecognized selector" warning during runtime. This is solved (I think) via message forwarding (isn't this how the responder chain works in the first place?):
As far as I can tell, all of this works fine for mouse events. But it doesn't work for key events. The CALayer never picks up any of the key events. NSViewController does pick up these events until an NSTextView (elsewhere on the window) gains focus. Once the NSTextView has focus, it never gives it up in favour of the NSViewController and the NSViewController no longer picks up key events. The NSViewController does pick up mouse events, regardless of the NSTextView.
Anyone knows where I went wrong? And thanks for reading all of this.
I am reading up about the responder chain and how to insert custom objects into the responder chain. But this is only working partially.
Maybe you know the answer?
I added a NSView to a xib file. Connected the NSView to a NSViewController and added a CALayer to the NSView. The idea is to have a responder chain like this: CALayer > NSViewController > NSView > NSWindow. The CALayer should respond first to all mouse and key events.
What I learned so far:
NSView and NSViewController are subclasses of NSResponder. However, NSViewController is not automatically part of the responder chain.
CALayer is a subclass of NSObject and therefore never automatically part of the responder chain.
To each of my subclasses of these three objects, I added
Code:
-(void)keyUp:(NSEvent *)event
{
NSLog(@"key down <class type>");
}
-(void) mouseUp:(NSEvent *)theEvent
{
NSLog(@"mouse down <class type>");
}
Code:
-(void) awakeFromNib
{
//code to add layer to view
//add viewcontroller to responder chain (call sequence is important)
[self setNextResponder:[[self view] nextResponder]];
[[self view] setNextResponder:self];
}
Code:
-(void) mouseDown:(NSEvent *)theEvent
{
if (!isFirstResponder)
{
[[[self view] window] makeFirstResponder:self];
isFirstResponder = YES;
}
//add layer to the responder chain
NSPoint pt = [[self view] convertPoint:[theEvent locationInWindow]
fromView:nil];
[[self view] setNextResponder:layer];
[layer setNextResponder:self];
}
Code:
-(BOOL) resignFirstResponder
{
[[self view] setNextResponder:[self nextResponder]];
[self setNextResponder:nil];
isFirstResponder = NO;
return YES;
}
-(BOOL) acceptsFirstResponder
{
isFirstResponder = YES;
return YES;
}
-(BOOL) makeFirstResponder
{
return [[[self view] window] makeFirstResponder:self];
}
Now, lets implement CALayer _like_ a NSReponder subclass.
Code:
-(BOOL) resignFirstResponder
{
return YES;
}
-(BOOL) acceptsFirstResponder
{
return YES;
}
-(void) setNextResponder:(NSResponder *)aResponder
{
nextResponder = aResponder; //nextResponder is an instance variable
}
-(NSResponder *) nextResponder
{
return nextResponder;
}
Code:
-(NSMethodSignature *) methodSignatureForSelector:(SEL)aSelector
{
return [[nextResponder class] instanceMethodSignatureForSelector:aSelector];
}
-(void) forwardInvocation:(NSInvocation *) invocation
{
SEL aSelector = [invocation selector];
[invocation invokeWithTarget:nextResponder];
}
Anyone knows where I went wrong? And thanks for reading all of this.