Swift 2:检测功能键按下

时间:2015-10-07 12:31:16

标签: macos swift2

我在Xcode 7(OS X 10.11)的Swift 2中编写程序,我想要它(这是ViewController类)能够检测用户何时按下功能键,特别是当应用程序在后台。我重写了acceptsFirstResponder

override var acceptsFirstResponder: Bool { return true }

我已实施keyUp:keyDown:

override func keyDown(theEvent: NSEvent) {
    print("keyDown:\n")
    let ch: NSString = theEvent.charactersIgnoringModifiers!
    if ch.length == 1 {
        let char: Int = Int(ch.characterAtIndex(0))
        if char == NSF7FunctionKey {
            prevSong(NSNull())
        }else if char == NSF8FunctionKey {
            playPause(NSNull())
        }else if char == NSF9FunctionKey {
            nextSong(NSNull())
        }else{
            self.nextResponder?.keyDown(theEvent)
        }
    }else{
        self.nextResponder?.keyDown(theEvent)
    }
}

override func keyUp(theEvent: NSEvent) {
    print("keyUp:\n")
    self.nextResponder?.keyUp(theEvent)
}

我最初拥有keyUp:中的所有代码,但我从未得到过" keyDown:"打印到控制台。另外,如果有人知道检测功能键的更好方法,请说出来。

为什么不检测按键?

2 个答案:

答案 0 :(得分:1)

看起来您正在尝试捕获媒体键(播放/暂停,前进,后退)。这些实际上不是功能键,它们是"硬件"键。 (如果您按住 fn ,则它们是功能键。如果您进入系统偏好设置>键盘窗格>键盘选项卡并启用"使用所有F1,F2等键作为标准功能键",然后它们是功能键并按住 fn 将它们切换到硬件键。)

其他地方有关于捕获这些媒体密钥的答案,例如herehere。他们都建议使用SPMediaKeyTap代码。

如果你真的对功能键感兴趣,你需要知道一些事情:

  • 应用通常不会在后台接收键盘事件。键盘事件仅转到活动应用程序。
  • 您可以使用全局事件监视器或Quartz事件点击来监控来自后台的关键事件,但前提是您的应用已获得用户批准才能访问辅助设备。这是为了防止键盘记录器和其他恶意软件。
  • 您可以使用RegisterEventHotKey()来实现更有限的方式从后台响应关键事件而无需辅助访问。它是Carbon API但不被弃用,因为它仍然是实现热键功能的正确方法。对媒体密钥等硬件密钥仍然没有帮助。

答案 1 :(得分:0)

由@Serneum撰写(Swift或Swift 2)here

@Joshua Nozzi here

也可在Objective-C中找到

请注意,按F8时,即使应用程序使用媒体键,iTunes仍会启动。如果您要禁用iTunes启动,请阅读this帖子(使用第三方应用)或this帖子(使用终端)(相同问题,不同答案)。

您可以通过继承NSApplication(在AppKit框架中为那些不知道的人)并覆盖sendEvent:NSEvent来捕获媒体密钥。

Swift代码(取自Serneum的答案):

import Cocoa

class Application: NSApplication {
    override func sendEvent(theEvent: NSEvent) {
        if theEvent.type == .SystemDefined && theEvent.subtype.rawValue == 8 {
            let keyCode = ((theEvent.data1 & 0xFFFF0000) >> 16)
            let keyFlags = (theEvent.data1 & 0x0000FFFF)
            // Get the key state. 0xA is KeyDown, OxB is KeyUp
            let keyState = (((keyFlags & 0xFF00) >> 8)) == 0xA
            let keyRepeat = (keyFlags & 0x1)
            mediaKeyEvent(Int32(keyCode), state: keyState, keyRepeat: Bool(keyRepeat))
        }
        super.sendEvent(theEvent)
        //note that without the above line the app doesn't respond to clicks or any keyboard events
    }

    func mediaKeyEvent(key: Int32, state: Bool, keyRepeat: Bool) {
        // Only send events on KeyDown. Without this check, these events will happen twice
        if (state) {
            switch(key) {
            case NX_KEYTYPE_PLAY:
                //F8 pressed
                break
            case NX_KEYTYPE_FAST:
                //F9 pressed
                break
            case NX_KEYTYPE_REWIND:
                //F7 pressed
                break
            default:
                break
            }
        }
    }
}

其他“硬件密钥”包括NX_KEYTYPE_BRIGHTNESS_DOWNNX_KEYTYPE_BRIGHTNESS_UPNX_KEYTYPE_CAPS_LOCKNX_KEYTYPE_EJECTNX_KEYTYPE_ILLUMINATION_UPNX_KEYTYPE_ILLUMINATION_DOWNNX_KEYTYPE_LAUNCH_PANELNX_KEYTYPE_MUTENX_KEYTYPE_SOUND_DOWNNX_KEYTYPE_SOUND_UP以及键盘上没有的其他内容,因此我无法确认。