简体   繁体   English

是否可以在 SwiftUI (macOS) 中禁用全局键盘事件的“funk”错误声音?

[英]Is it possible to disable "funk" error sound on global keyboard events in SwiftUI (macOS)?

I've started a SwiftUI project (it is a macOS tray application) that relies on global keyboard events (even when my application is minimized).我已经启动了一个依赖全局键盘事件(即使我的应用程序被最小化)的 SwiftUI 项目(它是一个 macOS 托盘应用程序)。 Specifically i care about the F3 and F4 keys.具体来说,我关心F3F4键。 While the keyboard events are registered correctly and my application is fully functional it is always playing that error "funk" sound when a key is pressed.虽然正确注册了键盘事件并且我的应用程序功能齐全,但它总是在按下键时播放错误“放克”声音。 Does anyone know how to fix this?有谁知道如何解决这一问题?

MyApp.swift MyApp.swift

import SwiftUI

@main
struct MyApp: App {
    @NSApplicationDelegateAdaptor(AppDelegate.self) var delegate;
    var body: some Scene {
        Settings {
            ContentView()
        }
    }
}

class AppDelegate: NSObject,NSApplicationDelegate {
    var statusItem: NSStatusItem!
    var popOver: NSPopover!
    
    func applicationDidFinishLaunching(_ notification: Notification){
        let contentView = ContentView()
        let popOver = NSPopover();
        popOver.behavior = .transient
        popOver.animates = true
        popOver.contentViewController = NSHostingController(rootView: contentView)
        popOver.setValue(true, forKeyPath: "shouldHideAnchor")
        
        self.popOver = popOver
        self.statusItem = NSStatusBar.system.statusItem(withLength: CGFloat(NSStatusItem.variableLength))
        
        let options: NSDictionary = [kAXTrustedCheckOptionPrompt.takeUnretainedValue() as String : true]
        let accessEnabled = AXIsProcessTrustedWithOptions(options)
        
        if !accessEnabled {
            print("Access Not Enabled")
        }

        // Here is where the global keypress event is registered
        NSEvent.addGlobalMonitorForEvents(matching: .keyDown) { (event) in
            if (event.keyCode == 99) {
                // do smth
            }else if (event.keyCode == 118) {
                // do smth else
                }
            }
        }
        
        if let MenuButton = self.statusItem.button {
            MenuButton.image = NSImage(systemSymbolName: "display.2", accessibilityDescription: nil)
            MenuButton.action = #selector(MenuButtonToggle)
        }
    }
    
    @objc func MenuButtonToggle(_ sender: AnyObject){
        if let button = self.statusItem.button {
            if self.popOver.isShown{
                self.popOver.performClose(sender)
            }else {
                self.popOver.show(relativeTo: button.bounds, of: button, preferredEdge: NSRectEdge.minY)
                self.popOver.contentViewController?.view.window?.makeKey()
            }
        }
    }
}

It looks like you can achieve this by assigning the keys through the view directly at least, perhaps this can work on your AppDelegate also but you need to override.看起来您至少可以通过直接通过视图分配键来实现这一点,也许这也可以在您的 AppDelegate 上工作,但您需要覆盖。

Here is a working example:这是一个工作示例:

struct KeyEventHandling: NSViewRepresentable {
    
    class KeyView: NSView {
            func isManagedByThisView(_ event: NSEvent) -> Bool {
                //...
                return true
            }
            
            override var acceptsFirstResponder: Bool { true }
            override func keyDown(with event: NSEvent) {
                if isManagedByThisView(event) {
                    print(">> key \(event.keyCode)")
                } else {
                    super.keyDown(with: event)
                }
            }
    }
    
    func makeNSView(context: Context) -> NSView {
        let view = KeyView()
        DispatchQueue.main.async { // wait till next event cycle
            view.window?.makeFirstResponder(view)
        }
        return view
    }
    
    func updateNSView(_ nsView: NSView, context: Context) {
    }
    
}

struct ContentView: View {
    var body: some View {
        KeyEventHandling()
    }
}

According to Documentation: "When you call super.keyDown(with: event) , the event goes up through the responder chain and if no other responders process it, causes beep sound."根据文档:“当您调用super.keyDown(with: event) ,事件会通过响应者链上升,如果没有其他响应者处理它,则会发出哔声。” Good Luck!祝你好运!

struct DisableBeepsView: NSViewRepresentable {
    class KeyView: NSView {
            func isManagedByThisView(_ event: NSEvent) -> Bool {
                return true
            }
            
            override var acceptsFirstResponder: Bool { true }
            override func keyDown(with event: NSEvent) {
                if isManagedByThisView(event) {
//                    print(">> key \(event.keyCode)")
                } else {
                    super.keyDown(with: event)
                }
            }
    }
    
    func makeNSView(context: Context) -> NSView {
        let view = KeyView()
        DispatchQueue.main.async { // wait till next event cycle
            view.window?.makeFirstResponder(view)
        }
        return view
    }
    
    func updateNSView(_ nsView: NSView, context: Context) {}
}

just locate DisableBeepsView() inside your View where you need to disable beep sound只需在您需要禁用哔声的视图中找到DisableBeepsView()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM