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