Macos 在Swift中捕获OSX媒体控制按钮

Macos 在Swift中捕获OSX媒体控制按钮,macos,swift,media-player,Macos,Swift,Media Player,我想让我的应用程序响应F7、F8和F9键盘媒体控制按钮 我知道这个可爱的库,但它不能与Swift结合使用:前几天我自己解决了这个问题。我在上面写了一封信,还有一封信 我将嵌入博客文章和最终代码,以防博客或要点消失注意:这是一篇很长的文章,详细介绍了类是如何构造的,以及如何调用应用程序委托中的其他方法。如果您想要的只是最终产品(MediaApplication类),请朝底部走。它就在XML和Info.plist信息之上 首先,要从媒体密钥中获取密钥事件,需要创建一个扩展NSApplication

我想让我的应用程序响应F7、F8和F9键盘媒体控制按钮


我知道这个可爱的库,但它不能与Swift结合使用:

前几天我自己解决了这个问题。我在上面写了一封信,还有一封信

我将嵌入博客文章和最终代码,以防博客或要点消失注意:这是一篇很长的文章,详细介绍了类是如何构造的,以及如何调用应用程序委托中的其他方法。如果您想要的只是最终产品(MediaApplication类),请朝底部走。它就在XML和Info.plist信息之上


首先,要从媒体密钥中获取密钥事件,需要创建一个扩展
NSApplication
的类。这很简单

import Cocoa

class MediaApplication: NSApplication {
}
接下来,我们需要重写
sendEvent()
函数

override func sendEvent(event: NSEvent) {
    if (event.type == .SystemDefined && event.subtype.rawValue == 8) {
        let keyCode = ((event.data1 & 0xFFFF0000) >> 16)
        let keyFlags = (event.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(event)
}
现在,我并不假装完全理解这里发生的事情,但我认为我有一个不错的想法
NSEvent
对象包含几个关键属性:
type
subtype
data1
data2
<代码>类型和
子类型
是不言自明的,但是
data1
data2
非常模糊。由于代码只使用
data1
,这就是我们将要研究的内容。据我所知,
data1
包含一个关键事件周围的所有数据。这意味着它包含密钥代码和任何密钥标志。按键标志似乎包含有关按键状态(按键是否按下?按键是否已释放?)以及按键是否按下并重复信号的信息。我还猜测,键代码和键标志都占据了
data1
中包含的一半数据,并且按位操作将这些数据分离为适当的变量。在获得所需的值之后,我们调用
mediaKeyEvent()
,稍后我将介绍它。无论将什么事件发送到我们的
MediaApplication
,我们都希望默认的
NSApplication
也能处理所有事件。为此,我们在函数末尾调用
super.sendEvent(event)
。现在,让我们来看一看<代码> MyAdKeIGIVER()/<代码> < /P> 这就是事情开始变得有趣的地方。首先,我们只想在
state
为true时检查按下的键,在本例中,只要按下键,就会检查该键。一旦我们开始检查按键,我们会寻找
NX\u按键类型\u播放
NX\u按键类型\u快速
,以及
NX\u按键类型\u回放
。如果它们的功能不明显,
NX\u KEYTYPE\u PLAY
是播放/暂停键,
NX\u KEYTYPE\u FAST
是下一个键,
NX\u KEYTYPE\u revend
是上一个键。现在,按下任何一个键都不会发生任何事情,所以让我们来看看一些可能的逻辑。我们将从一个简单的场景开始

case NX_KEYTYPE_PLAY:
    print("Play")
    break
有了此代码,当应用程序检测到已按下播放/暂停键时,您将看到控制台上打印的“播放”。很简单,对吧?让我们通过调用应用程序的
nsapplicationelegate
中的函数来增加赌注。首先,我们假设您的
nsapplicationelegate
有一个名为
printMessage
的函数。我们将在进行过程中对其进行修改,因此请密切关注这些更改。它们将是次要的,但更改将影响从
mediaEventKey
调用它们的方式

func printMessage() {
    print("Hello World")
}
这是最简单的情况。调用
printMessage()
时,您将在控制台中看到“Hello World”。您可以通过调用您的
nsapplicationelegate
上的
performSelector
来调用它,该应用程序可通过
MediaApplication
访问
performSelector
接受一个
选择器
,它只是
nsapplicationelegate
中函数的名称

case NX_KEYTYPE_PLAY:
    delegate!.performSelector("printMessage")
    break
现在,当应用程序检测到已按下播放/暂停键时,您将看到控制台上打印的“Hello World”。让我们用一个新版本的
printMessage
来提升性能,它接受了一个参数

func printMessage(arg: String) {
    print(arg)
}
case NX_KEYTYPE_PLAY:
    delegate!.performSelector("printMessage:", withObject: "Hello World")
    break
现在的想法是,如果调用
printMessage(“helloworld”)
,您将在控制台中看到“helloworld”。我们现在可以修改
performSelector
调用来处理传入参数

func printMessage(arg: String) {
    print(arg)
}
case NX_KEYTYPE_PLAY:
    delegate!.performSelector("printMessage:", withObject: "Hello World")
    break
关于这一变化,有几件事需要注意。首先,必须注意添加到
选择器的
。这将在函数名发送到委托时将其与参数分离。它的工作原理不太重要,不需要记住,但它与调用
printMessage:“helloworld”
的代理类似。我相当肯定这不是100%正确的,因为它可能会使用某种类型的对象ID,但我没有深入挖掘细节。无论如何,重要的是要记住在传递参数时添加
。。第二件需要注意的事情是,我们添加了一个
withObject
参数
withObject
AnyObject?
作为值。在本例中,我们只需传入一个
字符串
,因为这就是
printMessage
要查找的内容。当应用程序检测到已按下播放/暂停键时,您仍应在控制台中看到“Hello World”。让我们来看最后一个用例:一个版本的
printMessage
,它接受的不是一个参数,而是两个参数

func printMessage(arg: String, _ arg2: String) {
    print(arg)
}
case NX_KEYTYPE_PLAY:
    delegate!.performSelector("printMessage::", withObject: "Hello", withObject: "World")
    break
现在,如果调用了
printMessage(“Hello”,“World”)
,您将在控制台中看到“Hello World”。我们现在可以修改
performSelector
调用来处理传入两个参数

func printMessage(arg: String, _ arg2: String) {
    print(arg)
}
case NX_KEYTYPE_PLAY:
    delegate!.performSelector("printMessage::", withObject: "Hello", withObject: "World")
    break
和以前一样,这里有两件事需要注意。首先,我们现在在
选择器的末尾添加两个
。像以前一样,这是为了让德莱加