Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are NSResponder's keyboard actions not being called?

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?

like image 353
kennyc Avatar asked Oct 16 '25 01:10

kennyc


1 Answers

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.

like image 173
Ken Thomases Avatar answered Oct 18 '25 16:10

Ken Thomases



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!