为什么没有调用NSResponder的键盘操作?

时间:2014-03-29 00:11:25

标签: objective-c macos cocoa appkit nsresponder

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

以下是设置:

  • Xcode 5.1 / 10.9
  • 基本Cocoa应用程序,只有Custom View添加到主窗口。
  • 此自定义视图只是NSView
  • STView
  • STView只会覆盖acceptsFirstResponder以返回YES

在此设置中,我的STView实例将按预期正确接收所有键盘事件(包括Ctl-AperformKeyEquivalent:中包含keyDown:修饰符的事件。下面的讨论都注释了这两种方法。)

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

每当使用修饰键按下Up箭头键时,也会调用Ctl-Up。当一个修饰键被保持时(e.x。:Ctl-Up)我希望能够调用适当的键盘动作方法。

前:

  • moveUp: - > scrollPageUp:(预期:Alt-Up
  • moveUp: - > moveToBeginningOfParagraph:(预期:Shift-Up
  • moveUp: - > moveUpAndModifySelection:(预期:Command-Up
  • moveUp: - > moveToBeginningOfDocument:(预期:NSApplication sendEvent

此模式会针对所有键/修饰符组合重复。

Apple的文档中的两个方面似乎相关:

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

(我可以看到通过NSApplication sendAction:to:from:传入的修饰键事件,但永远不会调用moveUpAndModifySelection:,继续沿着视图层次结构,我希望在阅读上面的文档之后。< / p>

文档提示可能会以不同方式处理文本编辑视图。这些键盘操作是否仅发送到编辑文本的视图?如果没有,那么当用户按下NSView时,如何在自定义Shift-Up课程中调用keyDown:这样的消息?

作为参考,我使用此图表进行键盘绑定,但坦率地说,我已尝试过几乎所有组合,无论是否列出:

在一天结束时,我可能会覆盖keyDown并手动处理我感兴趣的所有组合,但我希望至少能理解为什么这不起作用按照我的意图。

(请注意,此处的预期应用是允许用户导航项目的网格状视图,非常类似于集合视图。)

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

更新

如果您在- (void)keyDown:(NSEvent *)theEvent { ... [self interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; }

中执行以下操作
moveUp:

然后&#34;纠正&#34;将在您的自定义视图上调用操作。我认为这是因为我感兴趣的操作是类似文本的操作,需要输入管理器解释并转换为适当的操作。

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

2 个答案:

答案 0 :(得分:3)

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

是的,在大多数情况下,有必要调用-[NSResponder interpretKeyEvents:]-[NSTextInputContext handleEvent:]来获取密钥绑定系统,以便向您发送绑定的操作方法。

至于您获得-moveUp:的原因,我在一个简单的自定义视图类中实现了以下内容:

- (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处理向上箭头键作为&#34;键盘界面控件&#34;的一部分。这是partially documented,但它不会明确调用-moveUp:等方法。显然,这就是它的实施方式。

答案 1 :(得分:2)

  

通过阅读该文档,系统似乎负责将关键事件映射到适当的关键操作。

没有“系统”。 NSResponder的工作原理如下:任意消息(只是一串字符)被放到响应者链的开头(无论键盘焦点是什么)。通常它什么都不做,并将其传递给“下一个”响应者。直到50或60次空操作之后,响应者链没有做任何事情,最终说“是的,我会回应那个!”它做了一些事情。一旦发生这种情况,响应者链中的任何内容都不会知道事件发生了。

响应者通常会触发另一个响应者。例如,如果您为keyDown:发送Cmd-S消息,它将一直无所事事,直到最终到达“另存为”菜单项,然后将saveDocument:置于响应者链的开始,重新遍历整个事情,直到它到达NSDocument,它将执行保存操作。

  

每当使用修饰键按下moveUp:箭头键时,也会调用Up。当一个修饰键被保持时(e.x。:Ctl-Up)我希望能够调用适当的键盘动作方法。

     

前:

     
      
  • Ctl-Up - &gt; moveUp:(预期:scrollPageUp:
  •   
  • Alt-Up - &gt; moveUp:(预期:moveToBeginningOfParagraph:
  •   
  • Shift-Up - &gt; moveUp:(预期:moveUpAndModifySelection:
  •   
  • Command-Up - &gt; moveUp:(预期:moveToBeginningOfDocument:
  •   

这并不令人困惑,响应者链对滚动视图或文本视图或任何内容都不了解。它只知道应用程序将keyDownmouseDown:消息推送到链上,毫秒后,scrollPageUp:消息进入链,或者可能没有。响应者链中有许多东西永远不会被使用。如果你需要它们,它们可以被触发,有些东西将由AppKit触发,但很多都没有。

请注意NSResponder中的方法列表主要是为了让代码自动完成的开发人员更轻松,并在使用GUI构建界面时填充可用操作列表。您可以将任何 @selector()放在响应者链上(只要它有一个sender参数)。并非所有正在使用的都被记录在案。

  

在一天结束时,我可能只是覆盖keyDown:并手动处理我感兴趣的所有组合,但我希望至少能理解为什么这对我不起作用。

是的。如果可能,您应keyDown:执行[self moveUpAndModifySelection:self];之类的操作。所以基本上是一个很大的switch语句或if语句没有太多的逻辑。

无论如何我就是这样做的:https://github.com/abhibeckert/Dux/blob/master/Dux/DuxTextView.m#L797