完整的 NSTextView 绑定:在 macOS 10.12 上损坏了吗?

NSTextView binding for complete: broken on macOS 10.12?

我有一个 NSTextView 子类 (Obj-C),它通过标准机制(实现 completionsForPartialWordRange:indexOfSelectedItem:rangeForUserCompletion 等)实现完成。过去,AppKit 会通过两个用户操作之一自动调用完成:按下 command-。 (命令句点),或按 esc(转义)。我刚刚切换到新的 "late 2016" MacBook Pro,同时从 10.11 升级到 10.12。代码完成在我的应用程序中不再有效。当没有人响应这些按键时,我刚从响应者链的深处接到 NSBeep() 的电话。 NSTextViewcomplete: 方法永远不会被命中(调试器说)。

我怀疑这是因为 Apple 所做的更改。我注意到 complete:(位于 https://developer.apple.com/reference/appkit/nstextview/1449359-complete?language=objc)的文档已更改;它以前说 complete: 是由 esc 触发的,但现在它说它是由 F5 触发的(这在我的机器上似乎也不起作用,但是功能键映射是总是很奇怪和难以理解,所以谁知道呢)。

我做了一些调查,覆盖了 doCommandForSelector: 以仅打印 AppKit 正在尝试的选择器,然后调用 super。事实证明,现在按 esc 会导致 doCommandForSelector:cancelOperation:cancel: 一起调用,然后按 command-。现在导致 cancel:。有点意思,因为那些键是用来取消面板等等的,但是这里没有涉及面板,没有取消的操作等等

我的问题是:让我恢复旧行为的最佳方法是什么?在 10.12 及更高版本上,换句话说,我仍然想要 esc 和 command-。在我的应用程序中调用 complete:。我找到了 Apple 关于通过 plist 文件更改键绑定的文档,但这似乎不是正确的方法。也许我应该做一个 keyDown: 覆盖,但我认为这些是不鼓励的,因为在键事件合并、国际键盘上键代码的解释等方面很复杂;我的理解是,干预事件处理的点通常太低了。相反,我认为我应该以某种方式修改 interpretKeyEvents: 的行为,以将我想要的键绑定到 complete:,但我不知道如何在代码中做到这一点。

这是一个覆盖 keyDown: 以使键绑定起作用的答案。不过,正如问题中提到的,我不确定这是 correct/recommended 做事的方式。

- (void)keyDown:(NSEvent *)event
{
    NSString *chars = [event charactersIgnoringModifiers];
    NSEventModifierFlags flags = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;

    if ([chars length] == 1)
    {
        unichar keyChar = [chars characterAtIndex:0];

        if ((keyChar == 0x1B) && (flags == 0))
        {
            // escape key pressed
            [self doCommandBySelector:@selector(complete:)];
            return;
        }
        if ((keyChar == '.') && (flags == NSEventModifierFlagCommand))
        {
            // command-. pressed
            [self doCommandBySelector:@selector(complete:)];
            return;
        }
    }

    [super keyDown:event];
}

如果有人给出更好的答案,我会很乐意选择。

在 Sierra 中,组合键 'opt-esc' 已取代 'esc' 作为 complete: 的标准绑定。如您所见,未修改的 'esc' 现在绑定到 cancelOperation:。对于我的应用程序,我正在记录新行为而不是覆盖它,因为我怀疑 Apple 有其原因进行如此烦人的更改。