防止事件监视器 OS X 中出现错误“放克”声音

Posted

技术标签:

【中文标题】防止事件监视器 OS X 中出现错误“放克”声音【英文标题】:Prevent error "funk" sound in event monitor OS X 【发布时间】:2016-12-26 17:28:36 【问题描述】:

我正在用 swift 编写一个应用程序,它位于屏幕顶部的菜单栏中。我需要一个全局和本地事件监视器来打开特定按键时的弹出窗口。本地事件监视器没有问题,但是当用户从 Finder 等应用程序中按下键盘命令 (cmd+shift+8) 时,弹出框会打开,但也会播放 mac 错误“Funk”声音。有什么办法可以禁用它吗?也许应用程序可以通过某种方式吃掉声音,或者将其注册为有效的键盘快捷键,从而永远不会播放声音?

代码如下:

        NSEvent.addGlobalMonitorForEvents(matching: NSEventMask.keyDown, handler: (event: NSEvent!) -> Void in
        if (event.keyCode == 28 && event.modifierFlags.contains(NSEventModifierFlags.command) && event.modifierFlags.contains(NSEventModifierFlags.shift))
            self.togglePopover(sender: self)
        
    );

    NSEvent.addLocalMonitorForEvents(matching: NSEventMask.keyDown, handler: (event: NSEvent!) -> NSEvent? in
        if (event.keyCode == 28 && event.modifierFlags.contains(NSEventModifierFlags.command) && event.modifierFlags.contains(NSEventModifierFlags.shift))
            self.togglePopover(sender: self)
        
        return event
    );

【问题讨论】:

1.我认为在NSWindow 中写一个空的keyDown 方法也可以。因为它假装窗口正在处理该事件,但实际上没有。不确定是否需要设置 acceptsFirstResponder 返回 true。我没试过这个。 2.或在系统设置(左上角菜单,第二项)中选择声音,并在第一个选项卡中将通知音效音量设置为0 我不认为 1 会起作用,因为当用户一直在窗口中时,不会发生此键盘快捷键。它可以在任何地方完成。 【参考方案1】:

我最终使用MASShortcut 作为解决此问题的临时解决方案。

【讨论】:

【参考方案2】:

    在您的addGlobalMonitorForEventsMatchingMask 处理程序中,保存当前的音量级别并降低两个通道的音量。您可以在调低音量之前或之后在处理程序中进行自己的事件处理。

    在从处理程序返回之前,恢复原始音量,但要包含延迟,让操作系统有时间处理事件(它会发送“funk”,但您不会听到)。

一个副作用:如果您正在听某些东西(例如,音乐),它也会被短暂静音。

我的活动代码:

[NSEvent addGlobalMonitorForEventsMatchingMask:NSEventMaskKeyDown
                                       handler:^(NSEvent *event) 
    if ( event.type == NSEventTypeKeyDown ) 
        if ( event.keyCode == 106 )  // F16
            // process the event here
            [self adjustVolume:@(NO)];
            [self performSelector:@selector(adjustVolume:) withObject:@(YES) afterDelay:0.3];
            // 0.2 seconds was too soon
        
    
];

我的音量调节代码:

- (void)adjustVolume:(NSNumber *)offOn

    // get audio device...
    AudioObjectPropertyAddress getDefaultOutputDevicePropertyAddress = 
        kAudioHardwarePropertyDefaultOutputDevice,
        kAudioObjectPropertyScopeGlobal,
        kAudioObjectPropertyElementMaster
    ;

    AudioDeviceID defaultOutputDeviceID;
    UInt32 infoSize = sizeof(defaultOutputDeviceID);
    AudioObjectGetPropertyData(kAudioObjectSystemObject,
                               &getDefaultOutputDevicePropertyAddress,
                               0, NULL,
                               &infoSize, &defaultOutputDeviceID);

    // structurs to access the left/right volume setting
    AudioObjectPropertyAddress volumePropertyAddress1 = 
        kAudioDevicePropertyVolumeScalar,
        kAudioDevicePropertyScopeOutput,
        1 /* left */
    ;
    AudioObjectPropertyAddress volumePropertyAddress2 = 
        kAudioDevicePropertyVolumeScalar,
        kAudioDevicePropertyScopeOutput,
        2 /* right */
    ;

    // save the original volume (assumes left/right are the same
    static Float32 volumeOriginal; // could be an iVar

    if ( offOn.boolValue == NO )  // turn off 

        UInt32 volumedataSize = sizeof(volumeOriginal);
        AudioObjectGetPropertyData(defaultOutputDeviceID,
                                   &volumePropertyAddress1,
                                   0, NULL,
                                   &volumedataSize, &volumeOriginal);
        //NSLog(@"volumeOriginal %f",volumeOriginal);

        // turn off both channels
        Float32 volume = 0.0;
        AudioObjectSetPropertyData(defaultOutputDeviceID,
                                   &volumePropertyAddress1,
                                   0, NULL,
                                   sizeof(volume), &volume);
        AudioObjectSetPropertyData(defaultOutputDeviceID,
                                   &volumePropertyAddress2,
                                   0, NULL,
                                   sizeof(volume), &volume);

     else  // restore

        //NSLog(@"restoring volume");
        AudioObjectSetPropertyData(defaultOutputDeviceID,
                                   &volumePropertyAddress1,
                                   0, NULL,
                                   sizeof(volumeOriginal), &volumeOriginal);
        AudioObjectSetPropertyData(defaultOutputDeviceID,
                                   &volumePropertyAddress2,
                                   0, NULL,
                                   sizeof(volumeOriginal), &volumeOriginal);
    

感谢 Thomas O'Dell 让我开始了 Change OS X system volume programmatically

【讨论】:

以上是关于防止事件监视器 OS X 中出现错误“放克”声音的主要内容,如果未能解决你的问题,请参考以下文章

防止在 OS X 中启动时出现 iCloud 打开文件对话框 [重复]

在 keydown 上禁用 WKWebView “funk”声音,但允许输入输入字段

大胆录音监视器声音加麦克风

如何监视 WPF 中的所有窗口,在所有窗口中订阅事件或者附加 UI

在 OS X 上使用 hdiutil 分离卷时出错

如何使用 Cocoa 在 OS X 中播放声音和平移?