NSResponder 定义了许多与键盘操作相关的操作,例如 moveUp:moveUpAndModifySelection:moveToBeginningOfLine: 。除了不是通过按修饰键触发的操作(例如 moveUp: 只是 Up 箭头键),我无法在我的自定义 NSView 上调用任何操作。

这是设置:

  • Xcode 5.1/10.9
  • 基本 Cocoa 应用程序,仅在主窗口中添加了 Custom View
  • 这个自定义 View 只是类 NSView
  • STView
  • STView 只是覆盖 acceptsFirstResponder 以返回 YES

  • 在这个设置中,我的 STView 实例将正确接收所有键盘事件(包括那些在 Ctl-AperformKeyEquivalent: 中都带有像 keyDown: 这样的修饰符的事件,正如预期的那样。(这两种方法都被注释掉以供下文讨论。)

    如果我提供 moveUp: 的实现,如 NSResponder 中所定义,那么当用户按下 moveUp: 箭头键时, Up 会被正确调用。

    令人困惑的是,每当使用修饰键按下 moveUp: 箭头键时,也会调用 Up。当按住修饰键(例如: Ctl-Up )时,我希望调用适当的键盘操作方法。

    前任:
  • Ctl-Up -> moveUp:(预期:scrollPageUp:)
  • Alt-Up -> moveUp:(预期:moveToBeginningOfParagraph:)
  • Shift-Up -> moveUp:(预期:moveUpAndModifySelection:)
  • Command-Up -> moveUp:(预期:moveToBeginningOfDocument:)

  • 对于所有键/修饰符组合,此模式都会重复。

    Apple 文档中的两个方面似乎相关:
  • Handling Keyboard Actions and Inserting Text
  • The Path of Key Events

  • 通读该文档,系统似乎负责将关键事件映射到相应的关键操作。事实上,当没有按下修饰键时,这对我有用。但是当按下修饰键时,事件就像任何其他事件一样被处理并通过正常的响应者链传递。

    (我可以看到通过 NSApplication sendEvent 传入的修饰键事件,尽管 NSApplication sendAction:to:from: 从未被调用,并继续向下查看 View 层次结构,鉴于我阅读了上述文档,我期望这样做。

    文档提示文本编辑 View 可能会有不同的处理方式。这些键盘操作是否仅发送到编辑文本的 View ?如果没有,那么当用户按下 moveUpAndModifySelection: 时,如何在他们的自定义 NSView 类上获得类似 Shift-Up 的消息?

    作为引用,我正在使用此图表进行键盘绑定(bind),但坦率地说,我已经尝试了几乎所有组合,无论是否列出:
  • Default Mac OS X System Key Bindings

  • 归根结底,我可能只是覆盖 keyDown: 并手动处理我感兴趣的所有组合,但我希望至少了解为什么这对我来说不起作用。

    (请注意,此处的预期应用程序是允许用户导航类似网格的项目 View ,很像集合 View 。)

    任何提示、建议或意见将不胜感激。

    更新:

    如果您在 keyDown 中执行以下操作
    - (void)keyDown:(NSEvent *)theEvent {
      ...
      [self interpretKeyEvents:[NSArray arrayWithObject:theEvent]];
    }
    

    然后将在您的自定义 View 上调用“正确”操作。我认为这是因为我感兴趣的 Action 是类似文本的 Action ,它需要输入管理器来解释并转换为适当的 Action 。

    我仍然不完全清楚为什么 moveUp: 被正确调用。响应者链中的谁识别出 Up 箭头键被按下,然后发出 moveUp: 消息?

    最佳答案

    这是对您的自我回答的一种回复,这更像是问题的延伸。

    是的,在大多数情况下,需要调用 -[NSResponder interpretKeyEvents:]-[NSTextInputContext handleEvent:] 来让键绑定(bind)系统向您发送绑定(bind)的操作方法。

    至于为什么你得到 -moveUp: ,我在一个简单的自定义 View 类中实现了以下内容:

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

    记录了以下调用堆栈:
    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 处理向上箭头键作为“键盘界面控制”的一部分。这是 partially documented ,但并没有明确表示它会调用诸如 -moveUp: 之类的方法。显然,这就是它的实现方式。

    关于objective-c - 为什么没有调用 NSResponder 的键盘操作?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22725329/

    10-10 20:30