退出全屏模式后如何接收 NSView 的键盘事件?
我对 NSView 进行子类化,并在应用程序完成启动时启动全屏模式。该视图可作为应用程序委托中的属性 fooView
使用。
// AppDelegate.m
- (void)applicationDidFinishLaunching:(NSNotification*)notification {
[[self window] makeKeyAndOrderFront:self];
[[self fooView] enterFullScreenMode:[NSScreen mainScreen] withOptions:nil];
}
类 FooView 本身实现了以下功能。
// FooView.m
- (void)keyDown:(NSEvent*)event {
NSLog(@"%@ %@ - %@", self.className, NSStringFromSelector(_cmd), event);
[self interpretKeyEvents:[NSArray arrayWithObject:event]];
}
- (void)cancelOperation:(id)sender {
NSLog(@"%@ %@ - %@", self.className, NSStringFromSelector(_cmd), sender);
[self exitFullScreenModeWithOptions:nil];
}
离开全屏模式后,视图不再接收键盘事件。为什么?
编辑:
这似乎与我退出全屏模式的方式有关。当我单击视图(而不是窗口)时,keyDown:
和 cancelOperation:
会做出以下响应。
I subclass an NSView and start full screen mode when the application finished launching. The view is available as the property fooView
in the application delegate.
// AppDelegate.m
- (void)applicationDidFinishLaunching:(NSNotification*)notification {
[[self window] makeKeyAndOrderFront:self];
[[self fooView] enterFullScreenMode:[NSScreen mainScreen] withOptions:nil];
}
The class FooView
itself implements the following functions.
// FooView.m
- (void)keyDown:(NSEvent*)event {
NSLog(@"%@ %@ - %@", self.className, NSStringFromSelector(_cmd), event);
[self interpretKeyEvents:[NSArray arrayWithObject:event]];
}
- (void)cancelOperation:(id)sender {
NSLog(@"%@ %@ - %@", self.className, NSStringFromSelector(_cmd), sender);
[self exitFullScreenModeWithOptions:nil];
}
After leaving the fullscreen mode, the view no longer receives keyboard events. Why?
Edit:
It seems to have something to do with how I exit the fullscreen mode. When I click into the view (not the window) the keyDown:
and cancelOperation:
do respond in the following.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
问题在于包含视图的窗口确实收到了任何键盘事件。离开全屏模式后,需要使窗口成为第一响应者。
The problem was that the window containing the view did receive any keyboard events. One needs to make the window the first responder after leaving the full screen mode.
我也有类似的问题。调用
-[NSView EnterFullScreenMode:withOptions:]
后,我无法接收所有 keyDown: 事件(特别是 Escape 键按下),直到单击全屏视图。我通过在
-[NSResponder doCommandBySelector:]
上设置符号断点来追踪问题,该断点显示堆栈跟踪:-[NSApplication sendEvent:]
-[NSWindow sendEvent:]
-[NSWindow keyDown:]
-[NSWindow doCommandBySelector:]
-[NSResponder doCommandBySelector:]
此后,系统会发出蜂鸣声,表明没有对象可以处理 keyDown 事件。
查看程序集输出表明它正在检查窗口的键和主要状态。根本问题是私有全屏窗口(视图由 AppKit 附加到该窗口)不会自动成为主窗口或关键窗口,因此不会按预期接收关键事件。
修复方法是在调用
-[NSView EnterFullScreenMode:withOptions:]
之后在私有全屏窗口上调用-makeKeyAndOrderFront:
。这是使用
-[NSObject PerformSelector:withObject:afterDelay:]
因为直到运行循环的下一次迭代,视图的window
属性才会设置为私有全屏窗口(而不是原来的窗口)。我不确定引用私人窗口的另一种方式。NSView
上的全屏模式的工作原理是 AppKit 从其原始窗口中删除视图,然后将其设置为_NSFullScreenWindow
类型的私有窗口的contentView
(其中没有标题栏)。这可以通过选择“调试”来看到。查看调试>当视图处于全屏模式时捕获视图层次结构。退出全屏会将其从_NSFullScreenWindow
中删除,并将其设置为原始窗口的contentView
。编辑:
我删除了上述之前的修复,因为在我重新配置处理关键事件的方式后它不再起作用。现在,应用程序中的关键事件通过窗口的内容视图进行处理,该视图是自定义 NSView 子类。 contentView 在应用启动时成为窗口的
initialResponder
和firstResponder
。这两个窗口属性在调用后必须再次设置:因为AppKit在全屏过程中改变了它们。
在我处理按键事件和全屏事件的 NSView 子类中:
我还遇到了一个问题,即当视图处于全屏模式时,键盘事件在 10.9.5 上仍然无法工作。
问题是用于全屏模式的私有窗口没有将其下一个响应者设置为原始窗口的下一个响应者,就像 AppKit 在 10.11+ 上自动执行的那样(我不确定10.10)。以下修复了该问题:
I was having a similar issue. After calling
-[NSView enterFullScreenMode:withOptions:]
I wasn't able to receive all keyDown: events (specifically Escape key down) until I clicked the full screen view.I tracked down the issue by setting an symbolic breakpoint on
-[NSResponder doCommandBySelector:]
, which showed the stack trace:-[NSApplication sendEvent:]
-[NSWindow sendEvent:]
-[NSWindow keyDown:]
-[NSWindow doCommandBySelector:]
-[NSResponder doCommandBySelector:]
After this point the system beep was played indicating there was no object that could handle the keyDown event.
Looking at the assembly output showed that it was checking for the window's key and main status. The root issue was that the private full screen window (that the view is attached to by AppKit) is not automatically made the main window or key window and thus does not receive key events as expected.
The fix was to call
-makeKeyAndOrderFront:
on the private full screen window after calling-[NSView enterFullScreenMode:withOptions:]
.This was doing using
-[NSObject performSelector:withObject:afterDelay:]
because it isn't until the next iteration of the run loop that the view'swindow
property is set to the private full screen window (instead of its original window). I'm not sure of another way to reference the private window.Full screen mode on
NSView
works by AppKit removing the view from its original window, then setting it as thecontentView
of a private window of type_NSFullScreenWindow
(which among other things does not have a title bar). This can be seen by selectingDebug > View Debugging > Capture View Hierarchy
while the view is in full screen mode. Exiting full screen removes it from the_NSFullScreenWindow
and sets it as thecontentView
of the original window.EDIT:
I removed my previous fix described above as it was no longer working after I reconfigured the way I handled key events. Now key events in the app are handled via the window's content view, which is a custom NSView subclass. The contentView is made the window's
initialResponder
andfirstResponder
at app launch. Both these window properties must be set again after calling:because AppKit changes them during the full screen process.
In my NSView subclass that handles key events as well as full-screen:
I also ran into an issue where keyboard events were still not working on 10.9.5 when the view was in full screen mode.
The issue was that the private window used for full-screen mode did not have its next responder set to the original window's next responder, like AppKit does automatically on 10.11+ (I'm unsure of the behavior on 10.10). The following fixed the issue: