Why are NSResponder's keyboard actions not being called?

appkit, cocoa, macos, nsresponder, objective-c

Solution

This is sort of a reply to your self-answer, which is more an extension of the question.

Yes, in most cases it is necessary to call `-[NSResponder interpretKeyEvents:]` or `-[NSTextInputContext handleEvent:]` to get the key bindings system to send you the bound action methods.

As to why you're getting `-moveUp:`, I implemented the following in a simple custom view class:

- (BOOL) acceptsFirstResponder
{
    return YES;
}

- (void) moveUp:(id)sender
{
    NSLog(@"%@", [NSThread callStackSymbols]);
}

That logged the following call stack:

0   TestKeyUp                           0x000000010000182d -[KeyView moveUp:] + 48
1   AppKit                              0x00007fff85e44012 -[NSWindow _processKeyboardUIKey:] + 325
2   AppKit                              0x00007fff85ab1075 -[NSWindow keyDown:] + 94
3   AppKit                              0x00007fff8589e206 forwardMethod + 104
4   AppKit                              0x00007fff8589e206 forwardMethod + 104
5   AppKit                              0x00007fff8596c0c7 -[NSWindow sendEvent:] + 8769
6   AppKit                              0x00007fff858a0afa -[NSApplication sendEvent:] + 4719
7   AppKit                              0x00007fff858376de -[NSApplication run] + 474
8   AppKit                              0x00007fff858303b0 NSApplicationMain + 364
9   TestKeyUp                           0x000000010000176d main + 33
10  TestKeyUp                           0x0000000100001744 start + 52
11  ???                                 0x0000000000000001 0x0 + 1

`NSWindow` handles the up-arrow key as part of "keyboard interface control". This is partially documented, but it's not explicit that it will invoke methods such as `-moveUp:`. Apparently, that's how it's implemented.

Problem

NSResponder defines numerous actions that are related to keyboard actions like `moveUp:`, `moveUpAndModifySelection:` and `moveToBeginningOfLine:`. With the exception of the actions that aren't triggered by pressing a modifier key (e.x. `moveUp:` is simply the `Up` arrow key) I can't get any of the actions to be called on my custom `NSView`. Here's the setup: - Xcode 5.1 / 10.9 - Basic Cocoa app with nothing more then a `Custom View` added to the main window. - This custom view is just an `NSView` of class `STView` - `STView` does nothing more than override `acceptsFirstResponder` to return `YES` In this setup, my `STView` instance will correctly receive all keyboard events (including those with a modifier like `Ctl-A` in both `performKeyEquivalent:` and `keyDown:`, as expected. (Both methods are commented out for the discussion below.) If I provide an implementation for `moveUp:`, as defined in `NSResponder` then `moveUp:` is correctly called when the user presses the `Up` arrow key. Confusingly, `moveUp:` is also called whenever the `Up` arrow key is pressed with a modifier key. When a modifier key is being held (e.x.: `Ctl-Up`) I would expect the appropriate keyboard action method to be called. Ex: - `Ctl-Up` -> `moveUp:` (expected: `scrollPageUp:`) - `Alt-Up` -> `moveUp:` (expected: `moveToBeginningOfParagraph:`) - `Shift-Up` -> `moveUp:` (expected: `moveUpAndModifySelection:`) - `Command-Up` -> `moveUp:` (expected: `moveToBeginningOfDocument:`) This pattern repeats itself for all key/modifier combinations. Two areas in Apple's documentation seem relevant: - Handling Keyboard Actions and Inserting Text - The Path of Key Events Reading through that documentation, it looks like the system is responsible for mapping key events to their appropriate key action. And indeed, this works for me when a modifier key is not pressed. But when a modifier key is pressed, then the event is just being handled like any other event and passed through the normal responder chain. (I can see the modifier key event coming in through `NSApplication sendEvent`, though `NSApplication sendAction:to:from:` is never called, and continuing down the view hierarchy, which I would expect given my reading of the documentation above. The documentation hints that text editing views might be treated differently. Are these keyboard actions only sent to views that edit text? If not, then how does one get a message like `moveUpAndModifySelection:` to be called on their custom `NSView` class when the user presses `Shift-Up`? For reference, I'm using this chart for keyboard bindings, though to be frank I've tried just about every combination, listed or not: - Default Mac OS X System Key Bindings At the end of the day, I could likely just override `keyDown:` and manually handle all the combinations I'm interested in, but I was hoping to at least understand why this isn't working as intended for me. (Note that the intended application here is to allow the user to navigate a grid-like view of items, much like a collection view.) Any tips, advice or comments would be much appreciated. Update: If you do the following in your `keyDown` ``` - (void)keyDown:(NSEvent *)theEvent { ... [self interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; } ``` Then the "correct" actions will be called on your custom view. I assume this is because the actions I'm interested in are text-like actions, which require the input manager to interpret and convert to their appropriate actions. It's still not entirely clear to me why `moveUp:` is properly getting called. Who in the responder chain is recognizing the `Up` arrow key being pressed and then sending out a `moveUp:` message?

Original source