【问题标题】:How can I handle ESC key in Cocoa app?如何处理 Cocoa 应用程序中的 ESC 键?
【发布时间】:2019-01-14 16:15:17
【问题描述】:

我让一个应用程序切换到全屏模式。我想使用 ESC 键来转义全屏模式,但是在运行时将菜单项绑定到 IB 中的 ESC 键被删除。如何保持 ESC 键绑定到菜单项?

【问题讨论】:

    标签: cocoa keyboard-shortcuts


    【解决方案1】:

    在 Cocoa 中处理转义键的首选方法是 @Josh Caswell said

    #pragma mark - NSResponder
    - (void)cancelOperation:(id)sender
    {
        [self exitFullScreen];
    }
    

    【讨论】:

    • 我也支持这个。
    【解决方案2】:

    捕获键盘事件的一种方法涉及子类化:

    1. 子类化您的全屏类(例如)NSView。
    2. 将方法- (void) keyDown:(NSEvent *)theEvent添加到子类实现中。
    3. 打开 InterfaceBuilder 并选择您之前创建的全屏类。
    4. 将其类更改为您的新子类。

    子类看起来像:

    MySubclass.h

    @interface MySubclass : NSView {
    }
    @end
    

    MySubclass.m

    #import <Carbon/Carbon.h>
    @implementation MySubclass
    - (void)keyDown:(NSEvent *)theEvent
    {       
        switch([theEvent keyCode]) {
            case kVK_Escape:
                NSLog(@"ESC");
                        // Call the full-screen mode method
                break;
            default:
                [super keyDown:theEvent];
        }
    }
    @end
    

    这不会将ESC 键绑定到菜单项,但它确实为您提供了等效的功能(并且更灵活,因为您可以拦截所有键盘事件)。

    【讨论】:

    • 另一个选项是实现cancelOperation:,它也响应⌘-。
    • 我继承了 nswindow 类,但在编辑 nstextfield 时仍然无法捕获 esc 键...
    • 如果(在 Objective-C 中)你 @import Carbon;#import &lt;Carbon/Carbon.h&gt;,常量 53 可以作为 kVK_Escape 使用。在 Swift 中,import Carbon.HIToolbox.
    【解决方案3】:

    许多人尝试实现 esc 键功能。响应者链中有 cancelOperation 来处理逃逸事件。

    //WRONG
    - (void)keyDown:(NSEvent *)event
    {
        //unichar character = 0;
        //if ([event type] == NSEventTypeKeyDown) {
        //    if ([[event charactersIgnoringModifiers] length] == 1) {
        //        character = [[event characters] characterAtIndex:0];
        //    }
        //}
    
        switch (character) {
            //THIS IS WRONG correct is to implement interpretKeyEvents+moveRight 
            //case NSRightArrowFunctionKey:
            //    [self moveSelectedIndexRight];
            //    break;
            //THIS IS WRONG correct is to implement interpretKeyEvents+ moveLeft 
            //case NSLeftArrowFunctionKey:
            //    [self moveSelectedIndexLeft];
            //    break;
            //THIS IS WRONG correct is to implement interpretKeyEvents+ moveLeft 
            //case NSCarriageReturnCharacter:
            //    [self dismissWithCurrentlySelectedToken];
            //    break;
            default:
                [self interpretKeyEvents:@[event]];
                [super keyDown:event]
                break;
        }
    }
    
    //CORRECT
    - (void)keyDown:(NSEvent *)event
    {
       [self interpretKeyEvents:@[event]];
       [super keyDown:event];
    }
    
    `/* Catch the commands interpreted by interpretKeyEvents:. Normally, if we don't implement (or any other view in the hierarchy implements) the selector, the system beeps. Menu navigation generally doesn't beep, so stop doCommandBySelector: from calling up t`he hierarchy just to stop the beep.
    */
    - (void)doCommandBySelector:(SEL)selector {
        if (   selector == @selector(moveRight:)
            || selector == @selector(moveLeft:)
            || selector == @selector(cancelOperation:)
            || selector == @selector(insertNewline:) )
        {
            [super doCommandBySelector:selector];
        }
    
        // do nothing, let the menu handle it (see call to super in -keyDown:)
        // But don't call super to prevent the system beep
    }
    - (void)cancelOperation:(id)sender
    {
        //do your escape stuff
    }
    
    - (void)insertNewline:(id)sender
    {
        //do your enter stuff
    }
    
    - (void)moveRight:(nullable id)sender
    {
        [self moveSelectedIndexRight];
    }
    
    - (void)moveLeft:(nullable id)sender
    {
        [self moveSelectedIndexLeft];
    }
    

    【讨论】:

      【解决方案4】:

      我需要在按下 ESC 时躲避 WKWebView 崩溃(?),所以我对它进行了子类化,并补充说:

      import Carbon.HIToolbox
      
      override func keyDown(with event: NSEvent) {
          if event.keyCode == UInt16(kVK_Escape) {
              //  We crash otherwise, so just close window
              self.window?.performClose(event)
          }
          else
          {
              // still here?
              super.keyDown(with: event)
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2011-08-25
        • 1970-01-01
        • 1970-01-01
        • 2012-04-30
        • 1970-01-01
        • 2017-09-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多