-->

How to forward keyboard up/down events from NSText

2020-07-18 05:56发布

问题:

I'm trying to simulate the way Spotlight works in Yosemite where the NSTextField (search field) always retains focus when hitting the up/down arrow keys and moves the tableview selection up and down.

I've implemented the following code:

- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)commandSelector
{
    if (commandSelector == @selector(moveUp:)) {
        // move up
        return YES;
    } else if(commandSelector == @selector(moveDown:)){
        // move down
        return YES;
    }

    return NO;
}

While I could use this to then move the row selection up/down with something like:

[self.tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:currentRow ± 1] byExtendingSelection:NO];

The problem I have is that I've created Section Header rows that should not be selectable and I've disabled selection of these rows using the NSTableViewDelegate method:

- (BOOL)tableView: (NSTableView *)tableView shouldSelectRow: (NSInteger)row

But what happens is that the selectRowIndexes:indexSetWithIndex:currentRowbyExtendingSelection: method selects the header row even though the delegate method says that the row can't be selected.

It seems you can still select rows programatically regardless of what the NSTableViewDelegate says. What I want is for the selection to jump the header rows.

If the NSTableView is the firstResponder then the built-in keyboard controls do skip the header rows.

So my question is is there a way to forward the up/down events to the NSTableView so that the built in mechanism for moving the selection works?

回答1:

The following works for me, but I'm not sure if there are any side effects.

- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)commandSelector
{
    if (commandSelector == @selector(moveUp:)) {
        // move up
        [_tableView keyDown:[NSApp currentEvent]];
        return YES;
    } else if(commandSelector == @selector(moveDown:)){
        // move down
        [_tableView keyDown:[NSApp currentEvent]];
        return YES;
    }

    return NO;
}


回答2:

Your -control:textView:doCommandBySelector: method should be in a controller which is either the table view's delegate or data source, or has access to them. Therefore, it can just check whether the row should be selected in much the same way that your delegate method would. (You can call the delegate method directly, but you don't necessarily have to.)

If that method is not in such a controller, it should forward the request to that controller.