Cocoa 键盘事件处理:Keyboard Actions

本文给出了在 Key Actions 阶段处理按键事件的两个具体例子。

前言

在 Cocoa 中,NSResponder 中的方法与键盘事件有默认绑定(参考 Default Mac OS X System Key Bindings)。可以通过重载 NSResponder 的方法或者在 keyDown: 中直接调用自定义方法来实现自定义操作。

具体实现

下文以 CurrencyX 为例:

  • 通过重载 ESC 绑定的 Command 实现

    • ESC 键返回汇率列表
  • 通过重载 keyDown: 实现:

    • 回车键定位到输入栏
    • 退格键定位到输入栏并且删除最后一个符号(如果有的话)
    • 数字键直接开始编辑输入栏
    • 字母键直接开始编辑搜索栏

重载 ESC 键对应的 Command

ESC 键对应的 Command 是 cancelOperation: ,因此只需在对应的 ViewController 中添加相应重载代码:

override func keyDown(with event: NSEvent) {
    self.interpretKeyEvents([event])
}

override func cancelOperation(sender: AnyObject?) {  
    // Pseudo-code 
    if is displaying search view {
        display currency list view        
    }
}

需要注意的是,在 View Controller 为 First Responder 时按键事件才会正确响应。

重载 keyDown:

override func keyDown(theEvent: NSEvent) {  
    // Pseudo-code 
''  let chars = event.charactersIgnoringModifiers
''  let modifiers = event.modifierFlags
    guard no modifiers && 
        chars means 'delete' 
        || chars means 'enter' 
        || chars is number && in normal mode
        || chars is alphabet && in search mode {
        super.keyDown(theEvent)
    } 
    focused text field
    if (chars means 'delete') {
        if (text filed has chars) {
            delete last char
        }
    } else if (chars means 'enter') {
        do nothing // we have focused anyway.
    } else {
        input chars
    }
    notify that text did change.
}

Tips: NSEvent 的 characters 属性是 String,而 NSEvent 和 NSText 定义的常量都是 Int,因此可以通过:

extension NSEvent {
    var keyCharacter: Int? {
        guard let char = charactersIgnoringModifiers?.utf16.first else {
            // Handling dead keys
            return nil
        }
        return Int(char)
    }
}

func isDeleteKeyDownEvent(theEvent: NSEvent) -> Bool {  
    if let char = theEvent.keyCharacter where char == NSDeleteCharacter {
        return true
    }
    return false
}

func isEnterKeyDownEvent(theEvent: NSEvent) -> Bool {  
    if let char = theEvent.keyCharacter where char == NSCarriageReturnCharacter {
        return true
    }
    return false
}

在 keyDown: 通过调用 isDeleteKeyDownEvent: 和 isEnterKeyDownEvent: 判断即可。

实际上在阅读文档之前,一直使用 theEvent.keyCode 直接与数字进行对比,只是这样代码可读性不高,实际上也是可行的方法。

讨论

可以阅读 Cocoa 应用内按键事件 进一步了解。

参考

广告

CurrencyX 是我们开发的 Mac 上小而美的汇率 app,售价¥18,如果你觉得文章有用,可以前往 App Store 买一个支持我们 点击下载 CurrencyX