Force NSPopover to not become first responder with NSTokenField

后端 未结 4 1539
天命终不由人
天命终不由人 2021-02-09 23:59

I\'m having a NSTokenField and I\'m providing a custom autocompletion inside the popover. Unfortunately as soon as the popover is shown it forces the NSTokenField to resign firs

4条回答
  •  失恋的感觉
    2021-02-10 00:45

    Unfortunately, there’s no clean way to do this. Luckily, though, I’ve done it the ugly way in Delicious Library 3—you need to put this method in a subclass of NSWindow, and make sure the document window in question is that subclass:

    - (BOOL)makeFirstResponder:(NSResponder *)responder;
    {
        // Prevent popover content view from forcing our current first responder to resign
        if (responder != self.firstResponder && [responder isKindOfClass:[NSView class]]) {
            NSWindow *const newFirstResponderWindow = ((NSView *)responder).window;
            NSWindow *currentFirstResponderWindow;
    
            NSResponder *const currentFirstResponder = self.firstResponder;
            if ([currentFirstResponder isKindOfClass:[NSWindow class]])
                currentFirstResponderWindow = (id)currentFirstResponder;
            else if ([currentFirstResponder isKindOfClass:[NSView class]])
                currentFirstResponderWindow = ((NSView *)currentFirstResponder).window;
    
            // Prevent some view in popover from stealing our first responder, but allow the user to explicitly activate it with a click on the popover.
            // Note that the current first responder may be in a child window, if it's a control in the "thick titlebar" area and we're currently full-screen.
            if (newFirstResponderWindow != self && newFirstResponderWindow != currentFirstResponderWindow && self.currentEvent.window != newFirstResponderWindow)
                for (NSView *responderView = (id)responder; responderView; responderView = responderView.superview)
                    if ([responderView conformsToProtocol:@protocol(LIPopoverFirstResponderStealingSuppression)] &&
                        ((id )responderView).suppressFirstResponderWhenPopoverShows)
                        return NO;
        }
    
        return [super makeFirstResponder:responder];
    }
    

    Now make sure the popover’s content view subclass implements this protocol:

    // NSPopover doesn't respect -acceptsFirstResponder of its content view (Radar 10666891).
    @protocol LIPopoverFirstResponderStealingSuppression 
    @property (readonly, nonatomic) BOOL suppressFirstResponderWhenPopoverShows;
    @end
    

    Please also file a bug with Apple to request NSPopover respect -acceptsFirstResponder of its content view; it is 100% the case that when multiple developers file bugs they get fixed.

提交回复
热议问题